".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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user