mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-14 16:38:35 -07:00
Archive: Support viewing Disk Images with Virtual Mount
This commit is contained in:
@@ -77,6 +77,13 @@ void archive_free(ArchiveApp* archive) {
|
|||||||
archive->thread = NULL;
|
archive->thread = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(archive->browser->disk_image) {
|
||||||
|
storage_virtual_quit(furi_record_open(RECORD_STORAGE));
|
||||||
|
furi_record_close(RECORD_STORAGE);
|
||||||
|
storage_file_free(archive->browser->disk_image);
|
||||||
|
archive->browser->disk_image = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// Loading
|
// Loading
|
||||||
loading_free(archive->loading);
|
loading_free(archive->loading);
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,8 @@ static void
|
|||||||
browser->is_root = is_root;
|
browser->is_root = is_root;
|
||||||
ArchiveTabEnum tab = archive_get_tab(browser);
|
ArchiveTabEnum tab = archive_get_tab(browser);
|
||||||
|
|
||||||
if((item_cnt == 0) && (archive_is_home(browser)) && (tab != ArchiveTabBrowser)) {
|
if((item_cnt == 0) && (archive_is_home(browser)) && (tab != ArchiveTabBrowser) &&
|
||||||
|
(tab != ArchiveTabDiskImage || !browser->disk_image)) {
|
||||||
archive_switch_tab(browser, browser->last_tab_switch_dir);
|
archive_switch_tab(browser, browser->last_tab_switch_dir);
|
||||||
} else if(!furi_string_start_with_str(browser->path, "/app:")) {
|
} else if(!furi_string_start_with_str(browser->path, "/app:")) {
|
||||||
with_view_model(
|
with_view_model(
|
||||||
@@ -512,7 +513,8 @@ void archive_favorites_move_mode(ArchiveBrowserView* browser, bool active) {
|
|||||||
|
|
||||||
static bool archive_is_dir_exists(FuriString* path) {
|
static bool archive_is_dir_exists(FuriString* path) {
|
||||||
if(furi_string_equal(path, STORAGE_INT_PATH_PREFIX) ||
|
if(furi_string_equal(path, STORAGE_INT_PATH_PREFIX) ||
|
||||||
furi_string_equal(path, STORAGE_EXT_PATH_PREFIX)) {
|
furi_string_equal(path, STORAGE_EXT_PATH_PREFIX) ||
|
||||||
|
furi_string_equal(path, STORAGE_MNT_PATH_PREFIX)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
bool state = false;
|
bool state = false;
|
||||||
@@ -592,7 +594,8 @@ void archive_switch_tab(ArchiveBrowserView* browser, InputKey key) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(tab_empty && tab != ArchiveTabBrowser && tab != ArchiveTabInternal) {
|
if(tab_empty && tab != ArchiveTabBrowser && tab != ArchiveTabInternal &&
|
||||||
|
(tab != ArchiveTabDiskImage || !browser->disk_image)) {
|
||||||
archive_switch_tab(browser, key);
|
archive_switch_tab(browser, key);
|
||||||
} else {
|
} else {
|
||||||
with_view_model(
|
with_view_model(
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ static const char* tab_default_paths[] = {
|
|||||||
[ArchiveTabU2f] = "/app:u2f",
|
[ArchiveTabU2f] = "/app:u2f",
|
||||||
[ArchiveTabApplications] = EXT_PATH("apps"),
|
[ArchiveTabApplications] = EXT_PATH("apps"),
|
||||||
[ArchiveTabSearch] = "/app:search",
|
[ArchiveTabSearch] = "/app:search",
|
||||||
|
[ArchiveTabDiskImage] = STORAGE_MNT_PATH_PREFIX,
|
||||||
[ArchiveTabInternal] = STORAGE_INT_PATH_PREFIX,
|
[ArchiveTabInternal] = STORAGE_INT_PATH_PREFIX,
|
||||||
[ArchiveTabBrowser] = STORAGE_EXT_PATH_PREFIX,
|
[ArchiveTabBrowser] = STORAGE_EXT_PATH_PREFIX,
|
||||||
};
|
};
|
||||||
@@ -54,6 +55,7 @@ static const ArchiveFileTypeEnum known_type[] = {
|
|||||||
[ArchiveTabU2f] = ArchiveFileTypeU2f,
|
[ArchiveTabU2f] = ArchiveFileTypeU2f,
|
||||||
[ArchiveTabApplications] = ArchiveFileTypeAppOrJs,
|
[ArchiveTabApplications] = ArchiveFileTypeAppOrJs,
|
||||||
[ArchiveTabSearch] = ArchiveFileTypeSearch,
|
[ArchiveTabSearch] = ArchiveFileTypeSearch,
|
||||||
|
[ArchiveTabDiskImage] = ArchiveFileTypeUnknown,
|
||||||
[ArchiveTabInternal] = ArchiveFileTypeUnknown,
|
[ArchiveTabInternal] = ArchiveFileTypeUnknown,
|
||||||
[ArchiveTabBrowser] = ArchiveFileTypeUnknown,
|
[ArchiveTabBrowser] = ArchiveFileTypeUnknown,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -81,6 +81,50 @@ static void archive_show_file(Loader* loader, const char* path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void archive_mount_disk_image(ArchiveBrowserView* browser, ArchiveFile_t* selected) {
|
||||||
|
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||||
|
File* disk_image = NULL;
|
||||||
|
do {
|
||||||
|
if(browser->disk_image) {
|
||||||
|
// Deinit and recycle File object
|
||||||
|
if(storage_virtual_quit(storage) != FSE_OK) break;
|
||||||
|
storage_file_close(browser->disk_image);
|
||||||
|
disk_image = browser->disk_image;
|
||||||
|
browser->disk_image = NULL;
|
||||||
|
} else {
|
||||||
|
disk_image = storage_file_alloc(storage);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!storage_file_open(
|
||||||
|
disk_image,
|
||||||
|
furi_string_get_cstr(selected->path),
|
||||||
|
FSAM_READ | FSAM_WRITE,
|
||||||
|
FSOM_OPEN_EXISTING))
|
||||||
|
break;
|
||||||
|
|
||||||
|
FS_Error init = storage_virtual_init(storage, disk_image);
|
||||||
|
if(init == FSE_ALREADY_OPEN) {
|
||||||
|
if(storage_virtual_quit(storage) == FSE_OK) {
|
||||||
|
init = storage_virtual_init(storage, disk_image);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(init != FSE_OK) break;
|
||||||
|
|
||||||
|
if(storage_virtual_mount(storage) != FSE_OK) {
|
||||||
|
storage_virtual_quit(storage);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
browser->disk_image = disk_image;
|
||||||
|
|
||||||
|
while(archive_get_tab(browser) != ArchiveTabDiskImage) {
|
||||||
|
archive_switch_tab(browser, TAB_LEFT);
|
||||||
|
}
|
||||||
|
} while(0);
|
||||||
|
if(disk_image && !browser->disk_image) storage_file_free(disk_image);
|
||||||
|
furi_record_close(RECORD_STORAGE);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selected, bool favorites) {
|
archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selected, bool favorites) {
|
||||||
Loader* loader = furi_record_open(RECORD_LOADER);
|
Loader* loader = furi_record_open(RECORD_LOADER);
|
||||||
@@ -226,9 +270,14 @@ bool archive_scene_browser_on_event(void* context, SceneManagerEvent event) {
|
|||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
case ArchiveBrowserEventFileMenuShow:
|
case ArchiveBrowserEventFileMenuShow:
|
||||||
archive_show_file(
|
if(selected->type == ArchiveFileTypeDiskImage &&
|
||||||
furi_record_open(RECORD_LOADER), furi_string_get_cstr(selected->path));
|
archive_get_tab(browser) != ArchiveTabDiskImage) {
|
||||||
furi_record_close(RECORD_LOADER);
|
archive_mount_disk_image(browser, selected);
|
||||||
|
} else {
|
||||||
|
archive_show_file(
|
||||||
|
furi_record_open(RECORD_LOADER), furi_string_get_cstr(selected->path));
|
||||||
|
furi_record_close(RECORD_LOADER);
|
||||||
|
}
|
||||||
archive_show_file_menu(browser, false, false);
|
archive_show_file_menu(browser, false, false);
|
||||||
consumed = true;
|
consumed = true;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ static const char* ArchiveTabNames[] = {
|
|||||||
[ArchiveTabU2f] = "U2F",
|
[ArchiveTabU2f] = "U2F",
|
||||||
[ArchiveTabApplications] = "Apps",
|
[ArchiveTabApplications] = "Apps",
|
||||||
[ArchiveTabSearch] = "Search",
|
[ArchiveTabSearch] = "Search",
|
||||||
|
[ArchiveTabDiskImage] = "Disk Image",
|
||||||
[ArchiveTabInternal] = "Internal",
|
[ArchiveTabInternal] = "Internal",
|
||||||
[ArchiveTabBrowser] = "Browser",
|
[ArchiveTabBrowser] = "Browser",
|
||||||
};
|
};
|
||||||
@@ -119,7 +120,7 @@ static void render_item_menu(Canvas* canvas, ArchiveBrowserViewModel* model) {
|
|||||||
if(selected->type != ArchiveFileTypeFolder) {
|
if(selected->type != ArchiveFileTypeFolder) {
|
||||||
archive_menu_add_item(
|
archive_menu_add_item(
|
||||||
menu_array_push_raw(model->context_menu),
|
menu_array_push_raw(model->context_menu),
|
||||||
"Show",
|
selected->type == ArchiveFileTypeDiskImage ? "Mount" : "Show",
|
||||||
ArchiveBrowserEventFileMenuShow);
|
ArchiveBrowserEventFileMenuShow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -209,7 +210,8 @@ static void draw_list(Canvas* canvas, ArchiveBrowserViewModel* model) {
|
|||||||
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));
|
||||||
file_type = file->type;
|
file_type = file->type;
|
||||||
bool ext = model->tab_idx == ArchiveTabBrowser ||
|
bool ext = model->tab_idx == ArchiveTabBrowser ||
|
||||||
model->tab_idx == ArchiveTabInternal || model->tab_idx == ArchiveTabSearch;
|
model->tab_idx == ArchiveTabInternal ||
|
||||||
|
model->tab_idx == ArchiveTabDiskImage || model->tab_idx == ArchiveTabSearch;
|
||||||
if(file_type == ArchiveFileTypeApplication) {
|
if(file_type == ArchiveFileTypeApplication) {
|
||||||
if(file->custom_icon_data) {
|
if(file->custom_icon_data) {
|
||||||
custom_icon_data = file->custom_icon_data;
|
custom_icon_data = file->custom_icon_data;
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ typedef enum {
|
|||||||
ArchiveTabU2f,
|
ArchiveTabU2f,
|
||||||
ArchiveTabApplications,
|
ArchiveTabApplications,
|
||||||
ArchiveTabSearch,
|
ArchiveTabSearch,
|
||||||
|
ArchiveTabDiskImage,
|
||||||
ArchiveTabInternal,
|
ArchiveTabInternal,
|
||||||
ArchiveTabBrowser,
|
ArchiveTabBrowser,
|
||||||
ArchiveTabTotal,
|
ArchiveTabTotal,
|
||||||
@@ -90,6 +91,7 @@ struct ArchiveBrowserView {
|
|||||||
InputKey last_tab_switch_dir;
|
InputKey last_tab_switch_dir;
|
||||||
bool is_root;
|
bool is_root;
|
||||||
FuriTimer* scroll_timer;
|
FuriTimer* scroll_timer;
|
||||||
|
File* disk_image;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
Reference in New Issue
Block a user