diff --git a/applications/settings/xtreme_settings/scenes/xtreme_settings_scene_start.c b/applications/settings/xtreme_settings/scenes/xtreme_settings_scene_start.c index bf9e4f1a4..1d196cfb6 100644 --- a/applications/settings/xtreme_settings/scenes/xtreme_settings_scene_start.c +++ b/applications/settings/xtreme_settings/scenes/xtreme_settings_scene_start.c @@ -8,6 +8,13 @@ static void xtreme_settings_scene_start_base_graphics_changed(VariableItem* item XTREME_SETTINGS()->sfw_mode = value; } +static void xtreme_settings_scene_start_asset_pack_changed(VariableItem* item) { + XtremeSettingsApp* app = variable_item_get_context(item); + uint8_t index = variable_item_get_current_value_index(item); + variable_item_set_current_value_text(item, index == 0 ? "OFF" : *asset_packs_get(app->asset_packs, index - 1)); + strlcpy(XTREME_SETTINGS()->asset_pack, index == 0 ? "" : *asset_packs_get(app->asset_packs, index - 1), MAX_PACK_NAME_LEN); +} + #define CYCLE_ANIMS_COUNT 13 const char* const cycle_anims_names[CYCLE_ANIMS_COUNT] = { "OFF", @@ -97,6 +104,26 @@ void xtreme_settings_scene_start_on_enter(void* context) { flipper_format_read_bool(subghz_range, "ignore_default_tx_region", &subghz_bypass, 1); } flipper_format_free(subghz_range); + + uint current_pack = 0; + asset_packs_init(app->asset_packs); + File* folder = storage_file_alloc(storage); + FileInfo info; + char* name = malloc(MAX_PACK_NAME_LEN); + do { + if (!storage_dir_open(folder, PACKS_DIR)) break; + while(true) { + if (!storage_dir_read(folder, &info, name, MAX_PACK_NAME_LEN)) break; + if(info.flags & FSF_DIRECTORY) { + char* copy = malloc(MAX_PACK_NAME_LEN); + strlcpy(copy, name, MAX_PACK_NAME_LEN); + asset_packs_push_back(app->asset_packs, copy); + if (strcmp(name, xtreme_settings->asset_pack) == 0) current_pack = asset_packs_size(app->asset_packs); + } + } + } while(false); + free(name); + storage_file_free(folder); furi_record_close(RECORD_STORAGE); item = variable_item_list_add( @@ -108,6 +135,15 @@ void xtreme_settings_scene_start_on_enter(void* context) { variable_item_set_current_value_index(item, xtreme_settings->sfw_mode); variable_item_set_current_value_text(item, xtreme_settings->sfw_mode ? "SFW" : "NSFW"); + item = variable_item_list_add( + var_item_list, + "Asset Pack", + asset_packs_size(app->asset_packs) + 1, + xtreme_settings_scene_start_asset_pack_changed, + app); + variable_item_set_current_value_index(item, current_pack); + variable_item_set_current_value_text(item, current_pack == 0 ? "OFF" : *asset_packs_get(app->asset_packs, current_pack - 1)); + item = variable_item_list_add( var_item_list, "Cycle Anims", @@ -171,6 +207,7 @@ void xtreme_settings_scene_start_on_exit(void* context) { XtremeSettingsApp* app = context; XTREME_SETTINGS_SAVE(); + XTREME_ASSETS_UPDATE(); Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN); DolphinStats stats = dolphin_stats(dolphin); @@ -182,5 +219,10 @@ void xtreme_settings_scene_start_on_exit(void* context) { } furi_record_close(RECORD_DOLPHIN); + asset_packs_it_t it; + for (asset_packs_it(it, app->asset_packs); !asset_packs_end_p(it); asset_packs_next(it)) { + free(*asset_packs_cref(it)); + } + asset_packs_clear(app->asset_packs); variable_item_list_reset(app->var_item_list); } diff --git a/applications/settings/xtreme_settings/xtreme_assets.c b/applications/settings/xtreme_settings/xtreme_assets.c index 49f67e97c..7357fc746 100644 --- a/applications/settings/xtreme_settings/xtreme_assets.c +++ b/applications/settings/xtreme_settings/xtreme_assets.c @@ -1,4 +1,9 @@ #include "xtreme_assets.h" +#include "assets_icons.h" +#include + +#define XTREME_ASSETS_COUNT 3 +Icon* loaded_icons[XTREME_ASSETS_COUNT]; XtremeAssets* xtreme_assets = NULL; @@ -14,13 +19,69 @@ void XTREME_ASSETS_UPDATE() { xtreme_assets = malloc(sizeof(XtremeAssets)); } XtremeSettings* xtreme_settings = XTREME_SETTINGS(); + if (xtreme_settings->sfw_mode) { xtreme_assets->passport_happy = &I_passport_happy1_46x49_sfw; - xtreme_assets->passport_okay = &I_passport_okay1_46x49_sfw; + xtreme_assets->passport_okay = &I_passport_okay1_46x49_sfw; xtreme_assets->passport_angry = &I_passport_bad1_46x49_sfw; } else { xtreme_assets->passport_happy = &I_flipper; - xtreme_assets->passport_okay = &I_flipper; + xtreme_assets->passport_okay = &I_flipper; xtreme_assets->passport_angry = &I_flipper; } + + for (int i = 0; i < XTREME_ASSETS_COUNT; i++) { + free_bmx_icon(loaded_icons[i]); + } + + if (xtreme_settings->asset_pack[0] == '\0') return; + FileInfo info; + FuriString* path = furi_string_alloc(); + Storage* storage = furi_record_open(RECORD_STORAGE); + path_concat(PACKS_DIR, xtreme_settings->asset_pack, path); + const char* pack = furi_string_get_cstr(path); + if (storage_common_stat(storage, pack, &info) == FSE_OK && info.flags & FSF_DIRECTORY) { + File* file = storage_file_alloc(storage); + int i = 0; + + swap_bmx_icon(&xtreme_assets->passport_happy, pack, "passport_happy.bmx", path, file, i++); + swap_bmx_icon(&xtreme_assets->passport_okay, pack, "passport_okay.bmx", path, file, i++); + swap_bmx_icon(&xtreme_assets->passport_angry, pack, "passport_angry.bmx", path, file, i++); + + storage_file_free(file); + } + furi_record_close(RECORD_STORAGE); + furi_string_free(path); +} + +void swap_bmx_icon(const Icon** replace, const char* base, const char* name, FuriString* path, File* file, int i) { + loaded_icons[i] = NULL; + path_concat(base, name, path); + if (storage_file_open(file, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) { + uint64_t size = storage_file_size(file) - 8; + int32_t width, height; + storage_file_read(file, &width, 4); + storage_file_read(file, &height, 4); + + Icon* icon = malloc(sizeof(Icon)); + FURI_CONST_ASSIGN(icon->frame_count, 1); + FURI_CONST_ASSIGN(icon->frame_rate, 0); + FURI_CONST_ASSIGN(icon->width, width); + FURI_CONST_ASSIGN(icon->height, height); + icon->frames = malloc(sizeof(const uint8_t*)); + FURI_CONST_ASSIGN_PTR(icon->frames[0], malloc(size)); + storage_file_read(file, (void*)icon->frames[0], size); + loaded_icons[i] = icon; + *replace = icon; + + storage_file_close(file); + } +} + +void free_bmx_icon(Icon* icon) { + if (icon != NULL) { + free((void*)icon->frames[0]); + free((void*)icon->frames); + free(icon); + } } diff --git a/applications/settings/xtreme_settings/xtreme_assets.h b/applications/settings/xtreme_settings/xtreme_assets.h index 157a0543b..002500bac 100644 --- a/applications/settings/xtreme_settings/xtreme_assets.h +++ b/applications/settings/xtreme_settings/xtreme_assets.h @@ -1,7 +1,10 @@ #pragma once +#include #include "xtreme_settings.h" -#include "assets_icons.h" +#include + +#define PACKS_DIR EXT_PATH("dolphin_custom") typedef struct { const Icon* passport_happy; @@ -12,3 +15,7 @@ typedef struct { XtremeAssets* XTREME_ASSETS(); void XTREME_ASSETS_UPDATE(); + +void swap_bmx_icon(const Icon** replace, const char* base, const char* name, FuriString* path, File* file, int i); + +void free_bmx_icon(Icon* icon); diff --git a/applications/settings/xtreme_settings/xtreme_settings.h b/applications/settings/xtreme_settings/xtreme_settings.h index 19c0803a9..bcef8f3ce 100644 --- a/applications/settings/xtreme_settings/xtreme_settings.h +++ b/applications/settings/xtreme_settings/xtreme_settings.h @@ -8,6 +8,8 @@ #include #include +#define MAX_PACK_NAME_LEN 32 + #define XTREME_SETTINGS_VERSION (1) #define XTREME_SETTINGS_PATH INT_PATH(XTREME_SETTINGS_FILE_NAME) #define XTREME_SETTINGS_MAGIC (0x69) @@ -15,7 +17,8 @@ typedef struct { int32_t cycle_anims; bool unlock_anims; - uint8_t sfw_mode; + bool sfw_mode; + char asset_pack[MAX_PACK_NAME_LEN]; } XtremeSettings; XtremeSettings* XTREME_SETTINGS(); diff --git a/applications/settings/xtreme_settings/xtreme_settings_app.h b/applications/settings/xtreme_settings/xtreme_settings_app.h index c953cfa68..a130083ac 100644 --- a/applications/settings/xtreme_settings/xtreme_settings_app.h +++ b/applications/settings/xtreme_settings/xtreme_settings_app.h @@ -8,10 +8,14 @@ #include #include #include "xtreme_settings.h" +#include "xtreme_assets.h" #include "scenes/xtreme_settings_scene.h" #include "dolphin/helpers/dolphin_state.h" #include "dolphin/dolphin.h" #include "dolphin/dolphin_i.h" +#include + +ARRAY_DEF(asset_packs, char*) typedef struct { Gui* gui; @@ -19,6 +23,7 @@ typedef struct { ViewDispatcher* view_dispatcher; VariableItemList* var_item_list; int dolphin_level; + asset_packs_t asset_packs; } XtremeSettingsApp; typedef enum {