".fap" extention in file browser and archive tab (#1812)
* Add .fap extention, and Applications tab * Using new icon, renaming tab to Apps * Change tabs order * Add first ugly implementation of in-app icons in archive browser * Starting using FAPLoader callback * Getting all metafata from fap * add app filename fallback * using fap_loader_item_callback in archive_list_item_cb * FAP-Loader: removed minimal allocation * Removed strange code Co-authored-by: SG <who.just.the.doctor@gmail.com> Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
parent
11681d8ee8
commit
d07c2dbe54
@ -5,6 +5,7 @@
|
|||||||
#include <core/common_defines.h>
|
#include <core/common_defines.h>
|
||||||
#include <core/log.h>
|
#include <core/log.h>
|
||||||
#include "gui/modules/file_browser_worker.h"
|
#include "gui/modules/file_browser_worker.h"
|
||||||
|
#include <fap_loader/fap_loader_app.h>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -351,16 +352,32 @@ void archive_add_app_item(ArchiveBrowserView* browser, const char* name) {
|
|||||||
ArchiveFile_t_clear(&item);
|
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) {
|
void archive_add_file_item(ArchiveBrowserView* browser, bool is_folder, const char* name) {
|
||||||
furi_assert(browser);
|
furi_assert(browser);
|
||||||
furi_assert(name);
|
furi_assert(name);
|
||||||
|
|
||||||
ArchiveFile_t item;
|
ArchiveFile_t item;
|
||||||
|
|
||||||
ArchiveFile_t_init(&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(
|
with_view_model(
|
||||||
browser->view, (ArchiveBrowserViewModel * model) {
|
browser->view, (ArchiveBrowserViewModel * model) {
|
||||||
files_array_push_back(model->files, item);
|
files_array_push_back(model->files, item);
|
||||||
|
@ -16,6 +16,7 @@ static const char* tab_default_paths[] = {
|
|||||||
[ArchiveTabInfrared] = ANY_PATH("infrared"),
|
[ArchiveTabInfrared] = ANY_PATH("infrared"),
|
||||||
[ArchiveTabBadUsb] = ANY_PATH("badusb"),
|
[ArchiveTabBadUsb] = ANY_PATH("badusb"),
|
||||||
[ArchiveTabU2f] = "/app:u2f",
|
[ArchiveTabU2f] = "/app:u2f",
|
||||||
|
[ArchiveTabApplications] = ANY_PATH("apps"),
|
||||||
[ArchiveTabBrowser] = STORAGE_ANY_PATH_PREFIX,
|
[ArchiveTabBrowser] = STORAGE_ANY_PATH_PREFIX,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -27,6 +28,7 @@ static const char* known_ext[] = {
|
|||||||
[ArchiveFileTypeInfrared] = ".ir",
|
[ArchiveFileTypeInfrared] = ".ir",
|
||||||
[ArchiveFileTypeBadUsb] = ".txt",
|
[ArchiveFileTypeBadUsb] = ".txt",
|
||||||
[ArchiveFileTypeU2f] = "?",
|
[ArchiveFileTypeU2f] = "?",
|
||||||
|
[ArchiveFileTypeApplication] = ".fap",
|
||||||
[ArchiveFileTypeUpdateManifest] = ".fuf",
|
[ArchiveFileTypeUpdateManifest] = ".fuf",
|
||||||
[ArchiveFileTypeFolder] = "?",
|
[ArchiveFileTypeFolder] = "?",
|
||||||
[ArchiveFileTypeUnknown] = "*",
|
[ArchiveFileTypeUnknown] = "*",
|
||||||
@ -41,6 +43,7 @@ static const ArchiveFileTypeEnum known_type[] = {
|
|||||||
[ArchiveTabInfrared] = ArchiveFileTypeInfrared,
|
[ArchiveTabInfrared] = ArchiveFileTypeInfrared,
|
||||||
[ArchiveTabBadUsb] = ArchiveFileTypeBadUsb,
|
[ArchiveTabBadUsb] = ArchiveFileTypeBadUsb,
|
||||||
[ArchiveTabU2f] = ArchiveFileTypeU2f,
|
[ArchiveTabU2f] = ArchiveFileTypeU2f,
|
||||||
|
[ArchiveTabApplications] = ArchiveFileTypeApplication,
|
||||||
[ArchiveTabBrowser] = ArchiveFileTypeUnknown,
|
[ArchiveTabBrowser] = ArchiveFileTypeUnknown,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -4,6 +4,8 @@
|
|||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <storage/storage.h>
|
#include <storage/storage.h>
|
||||||
|
|
||||||
|
#define FAP_MANIFEST_MAX_ICON_SIZE 32
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ArchiveFileTypeIButton,
|
ArchiveFileTypeIButton,
|
||||||
ArchiveFileTypeNFC,
|
ArchiveFileTypeNFC,
|
||||||
@ -13,6 +15,7 @@ typedef enum {
|
|||||||
ArchiveFileTypeBadUsb,
|
ArchiveFileTypeBadUsb,
|
||||||
ArchiveFileTypeU2f,
|
ArchiveFileTypeU2f,
|
||||||
ArchiveFileTypeUpdateManifest,
|
ArchiveFileTypeUpdateManifest,
|
||||||
|
ArchiveFileTypeApplication,
|
||||||
ArchiveFileTypeFolder,
|
ArchiveFileTypeFolder,
|
||||||
ArchiveFileTypeUnknown,
|
ArchiveFileTypeUnknown,
|
||||||
ArchiveFileTypeLoading,
|
ArchiveFileTypeLoading,
|
||||||
@ -21,33 +24,56 @@ typedef enum {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
FuriString* path;
|
FuriString* path;
|
||||||
ArchiveFileTypeEnum type;
|
ArchiveFileTypeEnum type;
|
||||||
|
uint8_t* custom_icon_data;
|
||||||
|
FuriString* custom_name;
|
||||||
bool fav;
|
bool fav;
|
||||||
bool is_app;
|
bool is_app;
|
||||||
} ArchiveFile_t;
|
} ArchiveFile_t;
|
||||||
|
|
||||||
static void ArchiveFile_t_init(ArchiveFile_t* obj) {
|
static void ArchiveFile_t_init(ArchiveFile_t* obj) {
|
||||||
obj->type = ArchiveFileTypeUnknown;
|
|
||||||
obj->is_app = false;
|
|
||||||
obj->fav = false;
|
|
||||||
obj->path = furi_string_alloc();
|
obj->path = furi_string_alloc();
|
||||||
|
obj->type = ArchiveFileTypeUnknown;
|
||||||
|
obj->custom_icon_data = NULL;
|
||||||
|
obj->custom_name = furi_string_alloc();
|
||||||
|
obj->fav = false;
|
||||||
|
obj->is_app = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ArchiveFile_t_init_set(ArchiveFile_t* obj, const ArchiveFile_t* src) {
|
static void ArchiveFile_t_init_set(ArchiveFile_t* obj, const ArchiveFile_t* src) {
|
||||||
obj->type = src->type;
|
|
||||||
obj->is_app = src->is_app;
|
|
||||||
obj->fav = src->fav;
|
|
||||||
obj->path = furi_string_alloc_set(src->path);
|
obj->path = furi_string_alloc_set(src->path);
|
||||||
|
obj->type = src->type;
|
||||||
|
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->is_app = src->is_app;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ArchiveFile_t_set(ArchiveFile_t* obj, const ArchiveFile_t* src) {
|
static void ArchiveFile_t_set(ArchiveFile_t* obj, const ArchiveFile_t* src) {
|
||||||
obj->type = src->type;
|
|
||||||
obj->is_app = src->is_app;
|
|
||||||
obj->fav = src->fav;
|
|
||||||
furi_string_set(obj->path, src->path);
|
furi_string_set(obj->path, src->path);
|
||||||
|
obj->type = src->type;
|
||||||
|
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;
|
||||||
|
obj->is_app = src->is_app;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ArchiveFile_t_clear(ArchiveFile_t* obj) {
|
static void ArchiveFile_t_clear(ArchiveFile_t* obj) {
|
||||||
furi_string_free(obj->path);
|
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(
|
ARRAY_DEF(
|
||||||
|
@ -20,6 +20,7 @@ static const char* flipper_app_name[] = {
|
|||||||
[ArchiveFileTypeBadUsb] = "Bad USB",
|
[ArchiveFileTypeBadUsb] = "Bad USB",
|
||||||
[ArchiveFileTypeU2f] = "U2F",
|
[ArchiveFileTypeU2f] = "U2F",
|
||||||
[ArchiveFileTypeUpdateManifest] = "UpdaterApp",
|
[ArchiveFileTypeUpdateManifest] = "UpdaterApp",
|
||||||
|
[ArchiveFileTypeApplication] = "Applications",
|
||||||
};
|
};
|
||||||
|
|
||||||
static void archive_loader_callback(const void* message, void* context) {
|
static void archive_loader_callback(const void* message, void* context) {
|
||||||
|
@ -14,6 +14,7 @@ static const char* ArchiveTabNames[] = {
|
|||||||
[ArchiveTabInfrared] = "Infrared",
|
[ArchiveTabInfrared] = "Infrared",
|
||||||
[ArchiveTabBadUsb] = "Bad USB",
|
[ArchiveTabBadUsb] = "Bad USB",
|
||||||
[ArchiveTabU2f] = "U2F",
|
[ArchiveTabU2f] = "U2F",
|
||||||
|
[ArchiveTabApplications] = "Apps",
|
||||||
[ArchiveTabBrowser] = "Browser",
|
[ArchiveTabBrowser] = "Browser",
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -29,6 +30,7 @@ static const Icon* ArchiveItemIcons[] = {
|
|||||||
[ArchiveFileTypeFolder] = &I_dir_10px,
|
[ArchiveFileTypeFolder] = &I_dir_10px,
|
||||||
[ArchiveFileTypeUnknown] = &I_unknown_10px,
|
[ArchiveFileTypeUnknown] = &I_unknown_10px,
|
||||||
[ArchiveFileTypeLoading] = &I_loading_10px,
|
[ArchiveFileTypeLoading] = &I_loading_10px,
|
||||||
|
[ArchiveFileTypeApplication] = &I_unknown_10px,
|
||||||
};
|
};
|
||||||
|
|
||||||
void archive_browser_set_callback(
|
void archive_browser_set_callback(
|
||||||
@ -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;
|
uint8_t x_offset = (model->move_fav && model->item_idx == idx) ? MOVE_OFFSET : 0;
|
||||||
|
|
||||||
ArchiveFileTypeEnum file_type = ArchiveFileTypeLoading;
|
ArchiveFileTypeEnum file_type = ArchiveFileTypeLoading;
|
||||||
|
uint8_t* custom_icon_data = NULL;
|
||||||
|
|
||||||
if(archive_is_item_in_array(model, idx)) {
|
if(archive_is_item_in_array(model, idx)) {
|
||||||
ArchiveFile_t* file = files_array_get(
|
ArchiveFile_t* file = files_array_get(
|
||||||
model->files, CLAMP(idx - model->array_offset, (int32_t)(array_size - 1), 0));
|
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;
|
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 {
|
} else {
|
||||||
furi_string_set(str_buf, "---");
|
furi_string_set(str_buf, "---");
|
||||||
}
|
}
|
||||||
@ -143,7 +156,13 @@ static void draw_list(Canvas* canvas, ArchiveBrowserViewModel* model) {
|
|||||||
canvas_set_color(canvas, ColorBlack);
|
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_draw_str(
|
||||||
canvas, 15 + x_offset, 24 + i * FRAME_HEIGHT, furi_string_get_cstr(str_buf));
|
canvas, 15 + x_offset, 24 + i * FRAME_HEIGHT, furi_string_get_cstr(str_buf));
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@ typedef enum {
|
|||||||
ArchiveTabIButton,
|
ArchiveTabIButton,
|
||||||
ArchiveTabBadUsb,
|
ArchiveTabBadUsb,
|
||||||
ArchiveTabU2f,
|
ArchiveTabU2f,
|
||||||
|
ArchiveTabApplications,
|
||||||
ArchiveTabBrowser,
|
ArchiveTabBrowser,
|
||||||
ArchiveTabTotal,
|
ArchiveTabTotal,
|
||||||
} ArchiveTabEnum;
|
} ArchiveTabEnum;
|
||||||
|
@ -1,34 +1,31 @@
|
|||||||
#include <furi.h>
|
#include <furi.h>
|
||||||
#include <gui/gui.h>
|
#include <gui/gui.h>
|
||||||
#include <gui/view_dispatcher.h>
|
#include <gui/view_dispatcher.h>
|
||||||
#include <gui/modules/loading.h>
|
|
||||||
#include <storage/storage.h>
|
#include <storage/storage.h>
|
||||||
|
#include <gui/modules/loading.h>
|
||||||
#include <dialogs/dialogs.h>
|
#include <dialogs/dialogs.h>
|
||||||
#include "elf_cpp/elf_hashtable.h"
|
|
||||||
#include <flipper_application/flipper_application.h>
|
#include <flipper_application/flipper_application.h>
|
||||||
|
#include "elf_cpp/elf_hashtable.h"
|
||||||
|
#include "fap_loader_app.h"
|
||||||
|
|
||||||
#define TAG "fap_loader_app"
|
#define TAG "fap_loader_app"
|
||||||
|
|
||||||
typedef struct {
|
struct FapLoader {
|
||||||
FlipperApplication* app;
|
FlipperApplication* app;
|
||||||
Storage* storage;
|
Storage* storage;
|
||||||
DialogsApp* dialogs;
|
DialogsApp* dialogs;
|
||||||
Gui* gui;
|
Gui* gui;
|
||||||
FuriString* fap_path;
|
FuriString* fap_path;
|
||||||
|
|
||||||
ViewDispatcher* view_dispatcher;
|
ViewDispatcher* view_dispatcher;
|
||||||
Loading* loading;
|
Loading* loading;
|
||||||
} FapLoader;
|
};
|
||||||
|
|
||||||
static bool fap_loader_item_callback(
|
bool fap_loader_load_name_and_icon(
|
||||||
FuriString* path,
|
FuriString* path,
|
||||||
void* context,
|
Storage* storage,
|
||||||
uint8_t** icon_ptr,
|
uint8_t** icon_ptr,
|
||||||
FuriString* item_name) {
|
FuriString* item_name) {
|
||||||
FapLoader* loader = context;
|
FlipperApplication* app = flipper_application_alloc(storage, &hashtable_api_interface);
|
||||||
furi_assert(loader);
|
|
||||||
|
|
||||||
FlipperApplication* app = flipper_application_alloc(loader->storage, &hashtable_api_interface);
|
|
||||||
|
|
||||||
FlipperApplicationPreloadStatus preload_res =
|
FlipperApplicationPreloadStatus preload_res =
|
||||||
flipper_application_preload_manifest(app, furi_string_get_cstr(path));
|
flipper_application_preload_manifest(app, furi_string_get_cstr(path));
|
||||||
@ -51,6 +48,16 @@ static bool fap_loader_item_callback(
|
|||||||
return load_success;
|
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) {
|
static bool fap_loader_run_selected_app(FapLoader* loader) {
|
||||||
furi_assert(loader);
|
furi_assert(loader);
|
||||||
|
|
||||||
@ -134,7 +141,7 @@ static bool fap_loader_select_app(FapLoader* loader) {
|
|||||||
const DialogsFileBrowserOptions browser_options = {
|
const DialogsFileBrowserOptions browser_options = {
|
||||||
.extension = ".fap",
|
.extension = ".fap",
|
||||||
.skip_assets = true,
|
.skip_assets = true,
|
||||||
.icon = &I_badusb_10px,
|
.icon = &I_unknown_10px,
|
||||||
.hide_ext = true,
|
.hide_ext = true,
|
||||||
.item_loader_callback = fap_loader_item_callback,
|
.item_loader_callback = fap_loader_item_callback,
|
||||||
.item_loader_context = loader,
|
.item_loader_context = loader,
|
||||||
@ -144,39 +151,44 @@ static bool fap_loader_select_app(FapLoader* loader) {
|
|||||||
loader->dialogs, loader->fap_path, loader->fap_path, &browser_options);
|
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));
|
FapLoader* loader = malloc(sizeof(FapLoader));
|
||||||
|
loader->fap_path = furi_string_alloc_set(path);
|
||||||
loader->storage = furi_record_open(RECORD_STORAGE);
|
loader->storage = furi_record_open(RECORD_STORAGE);
|
||||||
loader->dialogs = furi_record_open(RECORD_DIALOGS);
|
loader->dialogs = furi_record_open(RECORD_DIALOGS);
|
||||||
loader->gui = furi_record_open(RECORD_GUI);
|
loader->gui = furi_record_open(RECORD_GUI);
|
||||||
|
|
||||||
loader->view_dispatcher = view_dispatcher_alloc();
|
loader->view_dispatcher = view_dispatcher_alloc();
|
||||||
loader->loading = loading_alloc();
|
loader->loading = loading_alloc();
|
||||||
|
|
||||||
view_dispatcher_attach_to_gui(
|
view_dispatcher_attach_to_gui(
|
||||||
loader->view_dispatcher, loader->gui, ViewDispatcherTypeFullscreen);
|
loader->view_dispatcher, loader->gui, ViewDispatcherTypeFullscreen);
|
||||||
view_dispatcher_add_view(loader->view_dispatcher, 0, loading_get_view(loader->loading));
|
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) {
|
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);
|
fap_loader_run_selected_app(loader);
|
||||||
} else {
|
} else {
|
||||||
loader->fap_path = furi_string_alloc_set(EXT_PATH("apps"));
|
loader = fap_loader_alloc(EXT_PATH("apps"));
|
||||||
|
|
||||||
while(fap_loader_select_app(loader)) {
|
while(fap_loader_select_app(loader)) {
|
||||||
view_dispatcher_switch_to_view(loader->view_dispatcher, 0);
|
view_dispatcher_switch_to_view(loader->view_dispatcher, 0);
|
||||||
fap_loader_run_selected_app(loader);
|
fap_loader_run_selected_app(loader);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
view_dispatcher_remove_view(loader->view_dispatcher, 0);
|
fap_loader_free(loader);
|
||||||
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);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
27
applications/main/fap_loader/fap_loader_app.h
Normal file
27
applications/main/fap_loader/fap_loader_app.h
Normal file
@ -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
|
Loading…
Reference in New Issue
Block a user