Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions applications/main/archive/helpers/archive_browser.c
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <core/common_defines.h>
#include <core/log.h>
#include "gui/modules/file_browser_worker.h"
#include <fap_loader/fap_loader_app.h>
#include <math.h>

static void
Expand Down Expand Up @@ -351,16 +352,32 @@ void archive_add_app_item(ArchiveBrowserView* browser, const char* name) {
ArchiveFile_t_clear(&item);
}

static bool archive_get_fap_meta(FuriString* file_path, FuriString* fap_name, uint8_t** icon_ptr) {
Storage* storage = furi_record_open(RECORD_STORAGE);
bool success = false;
if(fap_loader_load_name_and_icon(file_path, storage, icon_ptr, fap_name)) {
success = true;
}
furi_record_close(RECORD_STORAGE);
return success;
}

void archive_add_file_item(ArchiveBrowserView* browser, bool is_folder, const char* name) {
furi_assert(browser);
furi_assert(name);

ArchiveFile_t item;

ArchiveFile_t_init(&item);
item.path = furi_string_alloc_set(name);
archive_set_file_type(&item, furi_string_get_cstr(browser->path), is_folder, false);

furi_string_set(item.path, name);
archive_set_file_type(&item, furi_string_get_cstr(browser->path), is_folder, false);
if(item.type == ArchiveFileTypeApplication) {
item.custom_icon_data = malloc(FAP_MANIFEST_MAX_ICON_SIZE);
if(!archive_get_fap_meta(item.path, item.custom_name, &item.custom_icon_data)) {
free(item.custom_icon_data);
item.custom_icon_data = NULL;
}
}
with_view_model(
browser->view, (ArchiveBrowserViewModel * model) {
files_array_push_back(model->files, item);
Expand Down
3 changes: 3 additions & 0 deletions applications/main/archive/helpers/archive_browser.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ static const char* tab_default_paths[] = {
[ArchiveTabInfrared] = ANY_PATH("infrared"),
[ArchiveTabBadUsb] = ANY_PATH("badusb"),
[ArchiveTabU2f] = "/app:u2f",
[ArchiveTabApplications] = ANY_PATH("apps"),
[ArchiveTabBrowser] = STORAGE_ANY_PATH_PREFIX,
};

Expand All @@ -27,6 +28,7 @@ static const char* known_ext[] = {
[ArchiveFileTypeInfrared] = ".ir",
[ArchiveFileTypeBadUsb] = ".txt",
[ArchiveFileTypeU2f] = "?",
[ArchiveFileTypeApplication] = ".fap",
[ArchiveFileTypeUpdateManifest] = ".fuf",
[ArchiveFileTypeFolder] = "?",
[ArchiveFileTypeUnknown] = "*",
Expand All @@ -41,6 +43,7 @@ static const ArchiveFileTypeEnum known_type[] = {
[ArchiveTabInfrared] = ArchiveFileTypeInfrared,
[ArchiveTabBadUsb] = ArchiveFileTypeBadUsb,
[ArchiveTabU2f] = ArchiveFileTypeU2f,
[ArchiveTabApplications] = ArchiveFileTypeApplication,
[ArchiveTabBrowser] = ArchiveFileTypeUnknown,
};

Expand Down
38 changes: 32 additions & 6 deletions applications/main/archive/helpers/archive_files.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include <furi.h>
#include <storage/storage.h>

#define FAP_MANIFEST_MAX_ICON_SIZE 32

typedef enum {
ArchiveFileTypeIButton,
ArchiveFileTypeNFC,
Expand All @@ -13,6 +15,7 @@ typedef enum {
ArchiveFileTypeBadUsb,
ArchiveFileTypeU2f,
ArchiveFileTypeUpdateManifest,
ArchiveFileTypeApplication,
ArchiveFileTypeFolder,
ArchiveFileTypeUnknown,
ArchiveFileTypeLoading,
Expand All @@ -21,33 +24,56 @@ typedef enum {
typedef struct {
FuriString* path;
ArchiveFileTypeEnum type;
uint8_t* custom_icon_data;
FuriString* custom_name;
bool fav;
bool is_app;
} ArchiveFile_t;

static void ArchiveFile_t_init(ArchiveFile_t* obj) {
obj->path = furi_string_alloc();
obj->type = ArchiveFileTypeUnknown;
obj->is_app = false;
obj->custom_icon_data = NULL;
obj->custom_name = furi_string_alloc();
obj->fav = false;
obj->path = furi_string_alloc();
obj->is_app = false;
}

static void ArchiveFile_t_init_set(ArchiveFile_t* obj, const ArchiveFile_t* src) {
obj->path = furi_string_alloc_set(src->path);
obj->type = src->type;
obj->is_app = src->is_app;
if(src->custom_icon_data) {
obj->custom_icon_data = malloc(FAP_MANIFEST_MAX_ICON_SIZE);
memcpy(obj->custom_icon_data, src->custom_icon_data, FAP_MANIFEST_MAX_ICON_SIZE);
} else {
obj->custom_icon_data = NULL;
}
obj->custom_name = furi_string_alloc_set(src->custom_name);
obj->fav = src->fav;
obj->path = furi_string_alloc_set(src->path);
obj->is_app = src->is_app;
}

static void ArchiveFile_t_set(ArchiveFile_t* obj, const ArchiveFile_t* src) {
furi_string_set(obj->path, src->path);
obj->type = src->type;
obj->is_app = src->is_app;
if(src->custom_icon_data) {
obj->custom_icon_data = malloc(FAP_MANIFEST_MAX_ICON_SIZE);
memcpy(obj->custom_icon_data, src->custom_icon_data, FAP_MANIFEST_MAX_ICON_SIZE);
} else {
obj->custom_icon_data = NULL;
}
furi_string_set(obj->custom_name, src->custom_name);
obj->fav = src->fav;
furi_string_set(obj->path, src->path);
obj->is_app = src->is_app;
}

static void ArchiveFile_t_clear(ArchiveFile_t* obj) {
furi_string_free(obj->path);
if(obj->custom_icon_data) {
free(obj->custom_icon_data);
obj->custom_icon_data = NULL;
}
furi_string_free(obj->custom_name);
}

ARRAY_DEF(
Expand Down
1 change: 1 addition & 0 deletions applications/main/archive/scenes/archive_scene_browser.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ static const char* flipper_app_name[] = {
[ArchiveFileTypeBadUsb] = "Bad USB",
[ArchiveFileTypeU2f] = "U2F",
[ArchiveFileTypeUpdateManifest] = "UpdaterApp",
[ArchiveFileTypeApplication] = "Applications",
};

static void archive_loader_callback(const void* message, void* context) {
Expand Down
23 changes: 21 additions & 2 deletions applications/main/archive/views/archive_browser_view.c
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ static const char* ArchiveTabNames[] = {
[ArchiveTabInfrared] = "Infrared",
[ArchiveTabBadUsb] = "Bad USB",
[ArchiveTabU2f] = "U2F",
[ArchiveTabApplications] = "Apps",
[ArchiveTabBrowser] = "Browser",
};

Expand All @@ -29,6 +30,7 @@ static const Icon* ArchiveItemIcons[] = {
[ArchiveFileTypeFolder] = &I_dir_10px,
[ArchiveFileTypeUnknown] = &I_unknown_10px,
[ArchiveFileTypeLoading] = &I_loading_10px,
[ArchiveFileTypeApplication] = &I_unknown_10px,
};

void archive_browser_set_callback(
Expand Down Expand Up @@ -124,12 +126,23 @@ static void draw_list(Canvas* canvas, ArchiveBrowserViewModel* model) {
uint8_t x_offset = (model->move_fav && model->item_idx == idx) ? MOVE_OFFSET : 0;

ArchiveFileTypeEnum file_type = ArchiveFileTypeLoading;
uint8_t* custom_icon_data = NULL;

if(archive_is_item_in_array(model, idx)) {
ArchiveFile_t* file = files_array_get(
model->files, CLAMP(idx - model->array_offset, (int32_t)(array_size - 1), 0));
path_extract_filename(file->path, str_buf, archive_is_known_app(file->type));
file_type = file->type;
if(file_type == ArchiveFileTypeApplication) {
if(file->custom_icon_data) {
custom_icon_data = file->custom_icon_data;
furi_string_set(str_buf, file->custom_name);
} else {
file_type = ArchiveFileTypeUnknown;
path_extract_filename(file->path, str_buf, archive_is_known_app(file->type));
}
} else {
path_extract_filename(file->path, str_buf, archive_is_known_app(file->type));
}
} else {
furi_string_set(str_buf, "---");
}
Expand All @@ -143,7 +156,13 @@ static void draw_list(Canvas* canvas, ArchiveBrowserViewModel* model) {
canvas_set_color(canvas, ColorBlack);
}

canvas_draw_icon(canvas, 2 + x_offset, 16 + i * FRAME_HEIGHT, ArchiveItemIcons[file_type]);
if(custom_icon_data) {
canvas_draw_bitmap(
canvas, 2 + x_offset, 16 + i * FRAME_HEIGHT, 11, 10, custom_icon_data);
} else {
canvas_draw_icon(
canvas, 2 + x_offset, 16 + i * FRAME_HEIGHT, ArchiveItemIcons[file_type]);
}
canvas_draw_str(
canvas, 15 + x_offset, 24 + i * FRAME_HEIGHT, furi_string_get_cstr(str_buf));

Expand Down
1 change: 1 addition & 0 deletions applications/main/archive/views/archive_browser_view.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ typedef enum {
ArchiveTabIButton,
ArchiveTabBadUsb,
ArchiveTabU2f,
ArchiveTabApplications,
ArchiveTabBrowser,
ArchiveTabTotal,
} ArchiveTabEnum;
Expand Down
68 changes: 40 additions & 28 deletions applications/main/fap_loader/fap_loader_app.c
Original file line number Diff line number Diff line change
@@ -1,34 +1,31 @@
#include <furi.h>
#include <gui/gui.h>
#include <gui/view_dispatcher.h>
#include <gui/modules/loading.h>
#include <storage/storage.h>
#include <gui/modules/loading.h>
#include <dialogs/dialogs.h>
#include "elf_cpp/elf_hashtable.h"
#include <flipper_application/flipper_application.h>
#include "elf_cpp/elf_hashtable.h"
#include "fap_loader_app.h"

#define TAG "fap_loader_app"

typedef struct {
struct FapLoader {
FlipperApplication* app;
Storage* storage;
DialogsApp* dialogs;
Gui* gui;
FuriString* fap_path;

ViewDispatcher* view_dispatcher;
Loading* loading;
} FapLoader;
};

static bool fap_loader_item_callback(
bool fap_loader_load_name_and_icon(
FuriString* path,
void* context,
Storage* storage,
uint8_t** icon_ptr,
FuriString* item_name) {
FapLoader* loader = context;
furi_assert(loader);

FlipperApplication* app = flipper_application_alloc(loader->storage, &hashtable_api_interface);
FlipperApplication* app = flipper_application_alloc(storage, &hashtable_api_interface);

FlipperApplicationPreloadStatus preload_res =
flipper_application_preload_manifest(app, furi_string_get_cstr(path));
Expand All @@ -51,6 +48,16 @@ static bool fap_loader_item_callback(
return load_success;
}

static bool fap_loader_item_callback(
FuriString* path,
void* context,
uint8_t** icon_ptr,
FuriString* item_name) {
FapLoader* fap_loader = context;
furi_assert(fap_loader);
return fap_loader_load_name_and_icon(path, fap_loader->storage, icon_ptr, item_name);
}

static bool fap_loader_run_selected_app(FapLoader* loader) {
furi_assert(loader);

Expand Down Expand Up @@ -134,7 +141,7 @@ static bool fap_loader_select_app(FapLoader* loader) {
const DialogsFileBrowserOptions browser_options = {
.extension = ".fap",
.skip_assets = true,
.icon = &I_badusb_10px,
.icon = &I_unknown_10px,
.hide_ext = true,
.item_loader_callback = fap_loader_item_callback,
.item_loader_context = loader,
Expand All @@ -144,39 +151,44 @@ static bool fap_loader_select_app(FapLoader* loader) {
loader->dialogs, loader->fap_path, loader->fap_path, &browser_options);
}

int32_t fap_loader_app(void* p) {
static FapLoader* fap_loader_alloc(const char* path) {
FapLoader* loader = malloc(sizeof(FapLoader));
loader->fap_path = furi_string_alloc_set(path);
loader->storage = furi_record_open(RECORD_STORAGE);
loader->dialogs = furi_record_open(RECORD_DIALOGS);
loader->gui = furi_record_open(RECORD_GUI);

loader->view_dispatcher = view_dispatcher_alloc();
loader->loading = loading_alloc();

view_dispatcher_attach_to_gui(
loader->view_dispatcher, loader->gui, ViewDispatcherTypeFullscreen);
view_dispatcher_add_view(loader->view_dispatcher, 0, loading_get_view(loader->loading));
return loader;
}

static void fap_loader_free(FapLoader* loader) {
view_dispatcher_remove_view(loader->view_dispatcher, 0);
loading_free(loader->loading);
view_dispatcher_free(loader->view_dispatcher);
furi_string_free(loader->fap_path);
furi_record_close(RECORD_GUI);
furi_record_close(RECORD_DIALOGS);
furi_record_close(RECORD_STORAGE);
free(loader);
}

int32_t fap_loader_app(void* p) {
FapLoader* loader;
if(p) {
loader->fap_path = furi_string_alloc_set((const char*)p);
loader = fap_loader_alloc((const char*)p);
fap_loader_run_selected_app(loader);
} else {
loader->fap_path = furi_string_alloc_set(EXT_PATH("apps"));

loader = fap_loader_alloc(EXT_PATH("apps"));
while(fap_loader_select_app(loader)) {
view_dispatcher_switch_to_view(loader->view_dispatcher, 0);
fap_loader_run_selected_app(loader);
};
}

view_dispatcher_remove_view(loader->view_dispatcher, 0);
loading_free(loader->loading);
view_dispatcher_free(loader->view_dispatcher);

furi_string_free(loader->fap_path);
furi_record_close(RECORD_GUI);
furi_record_close(RECORD_DIALOGS);
furi_record_close(RECORD_STORAGE);
free(loader);
fap_loader_free(loader);
return 0;
}
}
27 changes: 27 additions & 0 deletions applications/main/fap_loader/fap_loader_app.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#pragma once
#include <storage/storage.h>

#ifdef __cplusplus
extern "C" {
#endif

typedef struct FapLoader FapLoader;

/**
* @brief Load name and icon from FAP file.
*
* @param path Path to FAP file.
* @param storage Storage instance.
* @param icon_ptr Icon pointer.
* @param item_name Application name.
* @return true if icon and name were loaded successfully.
*/
bool fap_loader_load_name_and_icon(
FuriString* path,
Storage* storage,
uint8_t** icon_ptr,
FuriString* item_name);

#ifdef __cplusplus
}
#endif