mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-06-21 20:42:15 -07:00
Merge remote-tracking branch '956MB:feat/asset-packs-ram-warning' into 956/prs #344
This commit is contained in:
@@ -322,6 +322,10 @@ MomentumApp* momentum_app_alloc() {
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, MomentumAppViewDialogEx, dialog_ex_get_view(app->dialog_ex));
|
||||
|
||||
app->widget = widget_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, MomentumAppViewWidget, widget_get_view(app->widget));
|
||||
|
||||
// Settings init
|
||||
|
||||
app->asset_pack_index = 0;
|
||||
@@ -450,6 +454,8 @@ void momentum_app_free(MomentumApp* app) {
|
||||
popup_free(app->popup);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, MomentumAppViewDialogEx);
|
||||
dialog_ex_free(app->dialog_ex);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, MomentumAppViewWidget);
|
||||
widget_free(app->widget);
|
||||
|
||||
// View Dispatcher and Scene Manager
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <gui/modules/number_input.h>
|
||||
#include <gui/modules/popup.h>
|
||||
#include <gui/modules/dialog_ex.h>
|
||||
#include <gui/modules/widget.h>
|
||||
|
||||
#include <momentum/asset_packs.h>
|
||||
#include <loader/loader_menu.h>
|
||||
@@ -63,7 +64,7 @@ typedef struct {
|
||||
NumberInput* number_input;
|
||||
Popup* popup;
|
||||
DialogEx* dialog_ex;
|
||||
|
||||
Widget* widget;
|
||||
CharList_t asset_pack_names;
|
||||
uint8_t asset_pack_index;
|
||||
CharList_t mainmenu_app_labels;
|
||||
@@ -107,6 +108,7 @@ typedef enum {
|
||||
MomentumAppViewNumberInput,
|
||||
MomentumAppViewPopup,
|
||||
MomentumAppViewDialogEx,
|
||||
MomentumAppViewWidget,
|
||||
} MomentumAppView;
|
||||
|
||||
bool momentum_app_apply(MomentumApp* app);
|
||||
|
||||
@@ -2,6 +2,8 @@ ADD_SCENE(momentum_app, start, Start)
|
||||
ADD_SCENE(momentum_app, interface, Interface)
|
||||
ADD_SCENE(momentum_app, interface_graphics, InterfaceGraphics)
|
||||
ADD_SCENE(momentum_app, interface_graphics_pack, InterfaceGraphicsPack)
|
||||
ADD_SCENE(momentum_app, interface_graphics_pack_warning, InterfaceGraphicsPackWarning)
|
||||
ADD_SCENE(momentum_app, interface_graphics_pack_warning_info, InterfaceGraphicsPackWarningInfo)
|
||||
ADD_SCENE(momentum_app, interface_mainmenu, InterfaceMainmenu)
|
||||
ADD_SCENE(momentum_app, interface_mainmenu_add, InterfaceMainmenuAdd)
|
||||
ADD_SCENE(momentum_app, interface_mainmenu_add_main, InterfaceMainmenuAddMain)
|
||||
|
||||
@@ -2,11 +2,29 @@
|
||||
|
||||
enum VarItemListIndex {
|
||||
VarItemListIndexAssetPack,
|
||||
VarItemListIndexPackWarning,
|
||||
VarItemListIndexAnimSpeed,
|
||||
VarItemListIndexCycleAnims,
|
||||
VarItemListIndexUnlockAnims,
|
||||
};
|
||||
|
||||
static bool check_asset_pack_folders(const char* pack_name) {
|
||||
if(pack_name == NULL) return false;
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FuriString* path = furi_string_alloc();
|
||||
bool result = false;
|
||||
|
||||
furi_string_printf(path, "%s/%s/Icons", ASSET_PACKS_PATH, pack_name);
|
||||
if(storage_dir_exists(storage, furi_string_get_cstr(path))) result = true;
|
||||
if(!result) {
|
||||
furi_string_printf(path, "%s/%s/Fonts", ASSET_PACKS_PATH, pack_name);
|
||||
if(storage_dir_exists(storage, furi_string_get_cstr(path))) result = true;
|
||||
}
|
||||
|
||||
furi_string_free(path);
|
||||
return result;
|
||||
}
|
||||
|
||||
void momentum_app_scene_interface_graphics_var_item_list_callback(void* context, uint32_t index) {
|
||||
MomentumApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
@@ -24,6 +42,12 @@ static void momentum_app_scene_interface_graphics_asset_pack_changed(VariableIte
|
||||
app->asset_pack_index = index;
|
||||
app->save_settings = true;
|
||||
app->apply_pack = true;
|
||||
|
||||
// Workaround to force scene reload to rebuild the list with/without pack warning and
|
||||
// return to 0 index ("Asset Pack").
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
scene_manager_next_scene(app->scene_manager, MomentumAppSceneInterfaceGraphics);
|
||||
scene_manager_set_scene_state(app->scene_manager, MomentumAppSceneInterfaceGraphics, 0);
|
||||
}
|
||||
|
||||
const char* const anim_speed_names[] = {
|
||||
@@ -118,6 +142,10 @@ void momentum_app_scene_interface_graphics_on_enter(void* context) {
|
||||
VariableItem* item;
|
||||
uint8_t value_index;
|
||||
|
||||
const char* selected_asset_pack =
|
||||
app->asset_pack_index == 0 ?
|
||||
"Default" :
|
||||
*CharList_get(app->asset_pack_names, app->asset_pack_index - 1);
|
||||
item = variable_item_list_add(
|
||||
var_item_list,
|
||||
"Asset Pack",
|
||||
@@ -125,11 +153,14 @@ void momentum_app_scene_interface_graphics_on_enter(void* context) {
|
||||
momentum_app_scene_interface_graphics_asset_pack_changed,
|
||||
app);
|
||||
variable_item_set_current_value_index(item, app->asset_pack_index);
|
||||
variable_item_set_current_value_text(
|
||||
item,
|
||||
app->asset_pack_index == 0 ?
|
||||
"Default" :
|
||||
*CharList_get(app->asset_pack_names, app->asset_pack_index - 1));
|
||||
variable_item_set_current_value_text(item, selected_asset_pack);
|
||||
|
||||
if(app->asset_pack_index > 0) {
|
||||
if(check_asset_pack_folders(selected_asset_pack)) {
|
||||
item = variable_item_list_add(var_item_list, "Size Warning", 0, NULL, app);
|
||||
variable_item_set_current_value_text(item, ">");
|
||||
}
|
||||
}
|
||||
|
||||
item = variable_item_list_add(
|
||||
var_item_list,
|
||||
@@ -183,6 +214,11 @@ bool momentum_app_scene_interface_graphics_on_event(void* context, SceneManagerE
|
||||
switch(event.event) {
|
||||
case VarItemListIndexAssetPack:
|
||||
scene_manager_next_scene(app->scene_manager, MomentumAppSceneInterfaceGraphicsPack);
|
||||
break;
|
||||
case VarItemListIndexPackWarning:
|
||||
scene_manager_next_scene(
|
||||
app->scene_manager, MomentumAppSceneInterfaceGraphicsPackWarning);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
#include "../momentum_app.h"
|
||||
|
||||
void momentum_app_scene_interface_graphics_pack_warning_widget_callback(
|
||||
GuiButtonType result,
|
||||
InputType type,
|
||||
void* context) {
|
||||
MomentumApp* app = context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
void momentum_app_scene_interface_graphics_pack_warning_on_enter(void* context) {
|
||||
MomentumApp* app = context;
|
||||
|
||||
widget_add_button_element(
|
||||
app->widget,
|
||||
GuiButtonTypeLeft,
|
||||
"Back",
|
||||
momentum_app_scene_interface_graphics_pack_warning_widget_callback,
|
||||
app);
|
||||
widget_add_button_element(
|
||||
app->widget,
|
||||
GuiButtonTypeRight,
|
||||
"Info",
|
||||
momentum_app_scene_interface_graphics_pack_warning_widget_callback,
|
||||
app);
|
||||
widget_add_text_box_element(
|
||||
app->widget, 0, 0, 128, 22, AlignCenter, AlignCenter, "\e#Size Warning\e#", false);
|
||||
widget_add_string_multiline_element(
|
||||
app->widget,
|
||||
64,
|
||||
33,
|
||||
AlignCenter,
|
||||
AlignCenter,
|
||||
FontSecondary,
|
||||
"Your selected pack contains\n"
|
||||
"Fonts & Icons, which remain\n"
|
||||
"loaded and use up memory.");
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, MomentumAppViewWidget);
|
||||
}
|
||||
|
||||
bool momentum_app_scene_interface_graphics_pack_warning_on_event(
|
||||
void* context,
|
||||
SceneManagerEvent event) {
|
||||
MomentumApp* app = context;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == GuiButtonTypeLeft) {
|
||||
return scene_manager_previous_scene(app->scene_manager);
|
||||
} else if(event.event == GuiButtonTypeRight) {
|
||||
scene_manager_next_scene(
|
||||
app->scene_manager, MomentumAppSceneInterfaceGraphicsPackWarningInfo);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void momentum_app_scene_interface_graphics_pack_warning_on_exit(void* context) {
|
||||
MomentumApp* app = context;
|
||||
widget_reset(app->widget);
|
||||
}
|
||||
+114
@@ -0,0 +1,114 @@
|
||||
#include "../momentum_app.h"
|
||||
|
||||
void momentum_app_scene_interface_graphics_pack_warning_info_widget_callback(
|
||||
GuiButtonType result,
|
||||
InputType type,
|
||||
void* context) {
|
||||
MomentumApp* app = context;
|
||||
if(type == InputTypeShort) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
}
|
||||
|
||||
void momentum_app_scene_interface_graphics_pack_warning_info_on_enter(void* context) {
|
||||
MomentumApp* app = context;
|
||||
|
||||
widget_add_button_element(
|
||||
app->widget,
|
||||
GuiButtonTypeLeft,
|
||||
"Exit",
|
||||
momentum_app_scene_interface_graphics_pack_warning_info_widget_callback,
|
||||
app);
|
||||
|
||||
const char* dirs[] = {"Fonts", "Icons"};
|
||||
const char* font_exts[] = {".u8f"};
|
||||
const char* icon_exts[] = {".bm", ".bmx"};
|
||||
const char** exts[] = {font_exts, icon_exts};
|
||||
const size_t ext_counts[] = {COUNT_OF(font_exts), COUNT_OF(icon_exts)};
|
||||
const char* selected_pack =
|
||||
app->asset_pack_index == 0 ?
|
||||
"Default" :
|
||||
*CharList_get(app->asset_pack_names, app->asset_pack_index - 1);
|
||||
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
FuriString* path = furi_string_alloc();
|
||||
FuriString** paths = NULL;
|
||||
size_t num_paths = 0;
|
||||
|
||||
for(size_t i = 0; i < COUNT_OF(dirs); i++) {
|
||||
FuriString** files = NULL;
|
||||
size_t num_files = 0;
|
||||
|
||||
furi_string_printf(path, "%s/%s/%s", ASSET_PACKS_PATH, selected_pack, dirs[i]);
|
||||
if(storage_dir_exists(storage, furi_string_get_cstr(path))) {
|
||||
if(storage_list_dir(
|
||||
storage,
|
||||
furi_string_get_cstr(path),
|
||||
&files,
|
||||
&num_files,
|
||||
true,
|
||||
exts[i],
|
||||
ext_counts[i])) {
|
||||
paths = realloc(paths, (num_paths + num_files) * sizeof(FuriString*));
|
||||
memcpy(&paths[num_paths], files, num_files * sizeof(FuriString*));
|
||||
num_paths += num_files;
|
||||
free(files);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t f_count = 0;
|
||||
size_t i_count = 0;
|
||||
for(size_t i = 0; i < num_paths; i++) {
|
||||
if(furi_string_start_with_str(paths[i], ASSET_PACKS_PATH)) {
|
||||
if(furi_string_search_str(paths[i], "/Fonts/") != FURI_STRING_FAILURE) {
|
||||
f_count++;
|
||||
} else if(furi_string_search_str(paths[i], "/Icons/") != FURI_STRING_FAILURE) {
|
||||
i_count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FuriString* title = furi_string_alloc();
|
||||
if(f_count > 0 && i_count > 0) {
|
||||
furi_string_printf(title, "%zu Fonts, %zu Icons", f_count, i_count);
|
||||
} else if(f_count > 0) {
|
||||
furi_string_printf(title, "%zu Fonts", f_count);
|
||||
} else if(i_count > 0) {
|
||||
furi_string_printf(title, "%zu Icons", i_count);
|
||||
}
|
||||
|
||||
widget_add_file_list_element(app->widget, 0, 12, 4, paths, num_paths, 0, 52, true);
|
||||
|
||||
widget_add_string_element(
|
||||
app->widget, 35, 57, AlignLeft, AlignCenter, FontPrimary, furi_string_get_cstr(title));
|
||||
|
||||
furi_string_free(title);
|
||||
furi_string_free(path);
|
||||
for(size_t i = 0; i < num_paths; i++) {
|
||||
furi_string_free(paths[i]);
|
||||
}
|
||||
free(paths);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, MomentumAppViewWidget);
|
||||
}
|
||||
|
||||
bool momentum_app_scene_interface_graphics_pack_warning_info_on_event(
|
||||
void* context,
|
||||
SceneManagerEvent event) {
|
||||
MomentumApp* app = context;
|
||||
|
||||
if((event.type == SceneManagerEventTypeCustom && event.event == GuiButtonTypeLeft) ||
|
||||
event.type == SceneManagerEventTypeBack) {
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, MomentumAppSceneInterfaceGraphics);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void momentum_app_scene_interface_graphics_pack_warning_info_on_exit(void* context) {
|
||||
MomentumApp* app = context;
|
||||
widget_reset(app->widget);
|
||||
}
|
||||
@@ -90,9 +90,9 @@ static void widget_element_file_list_draw(Canvas* canvas, WidgetElement* element
|
||||
|
||||
size_t scroll_counter = model->scroll_counter;
|
||||
scroll_counter =
|
||||
i == 0 ? (model->count > model->lines &&
|
||||
(scroll_counter < SCROLL_DELAY ? 0 : scroll_counter - SCROLL_DELAY)) :
|
||||
0;
|
||||
i == 0 && model->count > model->lines ?
|
||||
(scroll_counter < SCROLL_DELAY ? 0 : scroll_counter - SCROLL_DELAY) :
|
||||
0;
|
||||
|
||||
elements_scrollable_text_line(
|
||||
canvas,
|
||||
|
||||
@@ -274,6 +274,27 @@ bool storage_dir_rewind(File* file);
|
||||
*/
|
||||
bool storage_dir_exists(Storage* storage, const char* path);
|
||||
|
||||
/**
|
||||
* @brief List the contents of a directory.
|
||||
*
|
||||
* @param storage pointer to a storage API instance.
|
||||
* @param path pointer to a zero-terminated string containing the path of the directory in question.
|
||||
* @param files pointer to an array of FuriString pointers to contain the file names.
|
||||
* @param num_files pointer to the number of files in the directory.
|
||||
* @param ignore_dirs if true, only files will be returned, not directories.
|
||||
* @param include_ext pointer to an array of zero-terminated strings of extensions to include.
|
||||
* @param ext_count the number of extensions in the include_ext array.
|
||||
* @return true if the directory was successfully listed, false otherwise.
|
||||
*/
|
||||
bool storage_list_dir(
|
||||
Storage* storage,
|
||||
const char* path,
|
||||
FuriString*** files,
|
||||
size_t* num_files,
|
||||
bool ignore_dirs,
|
||||
const char** include_ext,
|
||||
size_t ext_count);
|
||||
|
||||
/******************* Common Functions *******************/
|
||||
|
||||
/**
|
||||
|
||||
@@ -440,6 +440,79 @@ bool storage_dir_exists(Storage* storage, const char* path) {
|
||||
|
||||
return exist;
|
||||
}
|
||||
|
||||
bool storage_list_dir(
|
||||
Storage* storage,
|
||||
const char* path,
|
||||
FuriString*** files,
|
||||
size_t* num_files,
|
||||
bool ignore_dirs,
|
||||
const char** include_ext,
|
||||
size_t ext_count) {
|
||||
furi_check(storage);
|
||||
furi_check(path);
|
||||
furi_check(files);
|
||||
furi_check(num_files);
|
||||
|
||||
FileInfo fileinfo;
|
||||
bool result = false;
|
||||
char* name = malloc(MAX_NAME_LENGTH);
|
||||
File* dir = storage_file_alloc(storage);
|
||||
|
||||
do {
|
||||
if(!storage_dir_open(dir, path)) break;
|
||||
|
||||
while(storage_dir_read(dir, &fileinfo, name, MAX_NAME_LENGTH)) {
|
||||
if(strcmp(name, ".") == 0 || strcmp(name, "..") == 0) continue;
|
||||
|
||||
if(file_info_is_dir(&fileinfo)) {
|
||||
if(!ignore_dirs) {
|
||||
*files = realloc(*files, (*num_files + 1) * sizeof(FuriString*));
|
||||
(*files)[*num_files] = furi_string_alloc_printf("%s/%s", path, name);
|
||||
(*num_files)++;
|
||||
}
|
||||
FuriString* subpath = furi_string_alloc_printf("%s/%s", path, name);
|
||||
storage_list_dir(
|
||||
storage,
|
||||
furi_string_get_cstr(subpath),
|
||||
files,
|
||||
num_files,
|
||||
ignore_dirs,
|
||||
include_ext,
|
||||
ext_count);
|
||||
furi_string_free(subpath);
|
||||
} else {
|
||||
bool add_file = (include_ext == NULL || ext_count == 0);
|
||||
|
||||
if(!add_file) {
|
||||
const char* ext = strrchr(name, '.');
|
||||
if(ext != NULL) {
|
||||
for(size_t i = 0; i < ext_count; i++) {
|
||||
if(strcasecmp(ext, include_ext[i]) == 0) {
|
||||
add_file = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(add_file) {
|
||||
*files = realloc(*files, (*num_files + 1) * sizeof(FuriString*));
|
||||
(*files)[*num_files] = furi_string_alloc_printf("%s/%s", path, name);
|
||||
(*num_files)++;
|
||||
}
|
||||
}
|
||||
}
|
||||
result = true;
|
||||
} while(false);
|
||||
|
||||
storage_dir_close(dir);
|
||||
storage_file_free(dir);
|
||||
free(name);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/****************** COMMON ******************/
|
||||
|
||||
FS_Error storage_common_timestamp(Storage* storage, const char* path, uint32_t* timestamp) {
|
||||
|
||||
@@ -3502,6 +3502,7 @@ Function,+,storage_get_next_filename,void,"Storage*, const char*, const char*, c
|
||||
Function,+,storage_get_pubsub,FuriPubSub*,Storage*
|
||||
Function,+,storage_int_backup,FS_Error,"Storage*, const char*"
|
||||
Function,+,storage_int_restore,FS_Error,"Storage*, const char*, StorageNameConverter"
|
||||
Function,+,storage_list_dir,_Bool,"Storage*, const char*, FuriString***, size_t*, _Bool, const char**, size_t"
|
||||
Function,+,storage_sd_format,FS_Error,Storage*
|
||||
Function,+,storage_sd_info,FS_Error,"Storage*, SDInfo*"
|
||||
Function,+,storage_sd_mount,FS_Error,Storage*
|
||||
|
||||
|
Reference in New Issue
Block a user