mirror of
https://github.com/DarkFlippers/unleashed-firmware.git
synced 2025-12-12 20:49:49 +04:00
[FL-3947] Pinning of settings options (#4077)
* feat: pinning settings in favorites * include archive in unit tests fw * change settings icon * update text with suggestions from the ui team * Small touch of constness --------- Co-authored-by: あく <alleteam@gmail.com> Co-authored-by: hedger <hedger@users.noreply.github.com> Co-authored-by: hedger <hedger@nanode.su>
This commit is contained in:
@@ -1,8 +1,9 @@
|
|||||||
#include "archive_apps.h"
|
#include "archive_apps.h"
|
||||||
#include "archive_browser.h"
|
#include "archive_browser.h"
|
||||||
|
|
||||||
static const char* known_apps[] = {
|
static const char* const known_apps[] = {
|
||||||
[ArchiveAppTypeU2f] = "u2f",
|
[ArchiveAppTypeU2f] = "u2f",
|
||||||
|
[ArchiveAppTypeSetting] = "setting",
|
||||||
};
|
};
|
||||||
|
|
||||||
ArchiveAppTypeEnum archive_get_app_type(const char* path) {
|
ArchiveAppTypeEnum archive_get_app_type(const char* path) {
|
||||||
@@ -36,6 +37,8 @@ bool archive_app_is_available(void* context, const char* path) {
|
|||||||
|
|
||||||
furi_record_close(RECORD_STORAGE);
|
furi_record_close(RECORD_STORAGE);
|
||||||
return file_exists;
|
return file_exists;
|
||||||
|
} else if(app == ArchiveAppTypeSetting) {
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -53,6 +56,9 @@ bool archive_app_read_dir(void* context, const char* path) {
|
|||||||
if(app == ArchiveAppTypeU2f) {
|
if(app == ArchiveAppTypeU2f) {
|
||||||
archive_add_app_item(browser, "/app:u2f/U2F Token");
|
archive_add_app_item(browser, "/app:u2f/U2F Token");
|
||||||
return true;
|
return true;
|
||||||
|
} else if(app == ArchiveAppTypeSetting) {
|
||||||
|
archive_add_app_item(browser, path);
|
||||||
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -75,6 +81,8 @@ void archive_app_delete_file(void* context, const char* path) {
|
|||||||
if(archive_is_favorite("/app:u2f/U2F Token")) {
|
if(archive_is_favorite("/app:u2f/U2F Token")) {
|
||||||
archive_favorites_delete("/app:u2f/U2F Token");
|
archive_favorites_delete("/app:u2f/U2F Token");
|
||||||
}
|
}
|
||||||
|
} else if(app == ArchiveAppTypeSetting) {
|
||||||
|
// can't delete a setting!
|
||||||
}
|
}
|
||||||
|
|
||||||
if(res) {
|
if(res) {
|
||||||
|
|||||||
@@ -4,12 +4,14 @@
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
ArchiveAppTypeU2f,
|
ArchiveAppTypeU2f,
|
||||||
|
ArchiveAppTypeSetting,
|
||||||
ArchiveAppTypeUnknown,
|
ArchiveAppTypeUnknown,
|
||||||
ArchiveAppsTotal,
|
ArchiveAppsTotal,
|
||||||
} ArchiveAppTypeEnum;
|
} ArchiveAppTypeEnum;
|
||||||
|
|
||||||
static const ArchiveFileTypeEnum app_file_types[] = {
|
static const ArchiveFileTypeEnum app_file_types[] = {
|
||||||
[ArchiveAppTypeU2f] = ArchiveFileTypeU2f,
|
[ArchiveAppTypeU2f] = ArchiveFileTypeU2f,
|
||||||
|
[ArchiveAppTypeSetting] = ArchiveFileTypeSetting,
|
||||||
[ArchiveAppTypeUnknown] = ArchiveFileTypeUnknown,
|
[ArchiveAppTypeUnknown] = ArchiveFileTypeUnknown,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
#define TAB_DEFAULT ArchiveTabFavorites // Start tab
|
#define TAB_DEFAULT ArchiveTabFavorites // Start tab
|
||||||
#define FILE_LIST_BUF_LEN 50
|
#define FILE_LIST_BUF_LEN 50
|
||||||
|
|
||||||
static const char* tab_default_paths[] = {
|
static const char* const tab_default_paths[] = {
|
||||||
[ArchiveTabFavorites] = "/app:favorites",
|
[ArchiveTabFavorites] = "/app:favorites",
|
||||||
[ArchiveTabIButton] = EXT_PATH("ibutton"),
|
[ArchiveTabIButton] = EXT_PATH("ibutton"),
|
||||||
[ArchiveTabNFC] = EXT_PATH("nfc"),
|
[ArchiveTabNFC] = EXT_PATH("nfc"),
|
||||||
@@ -20,7 +20,7 @@ static const char* tab_default_paths[] = {
|
|||||||
[ArchiveTabBrowser] = STORAGE_EXT_PATH_PREFIX,
|
[ArchiveTabBrowser] = STORAGE_EXT_PATH_PREFIX,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const char* known_ext[] = {
|
static const char* const known_ext[] = {
|
||||||
[ArchiveFileTypeIButton] = ".ibtn",
|
[ArchiveFileTypeIButton] = ".ibtn",
|
||||||
[ArchiveFileTypeNFC] = ".nfc",
|
[ArchiveFileTypeNFC] = ".nfc",
|
||||||
[ArchiveFileTypeSubGhz] = ".sub",
|
[ArchiveFileTypeSubGhz] = ".sub",
|
||||||
@@ -34,6 +34,7 @@ static const char* known_ext[] = {
|
|||||||
[ArchiveFileTypeFolder] = "?",
|
[ArchiveFileTypeFolder] = "?",
|
||||||
[ArchiveFileTypeUnknown] = "*",
|
[ArchiveFileTypeUnknown] = "*",
|
||||||
[ArchiveFileTypeAppOrJs] = ".fap|.js",
|
[ArchiveFileTypeAppOrJs] = ".fap|.js",
|
||||||
|
[ArchiveFileTypeSetting] = "?",
|
||||||
};
|
};
|
||||||
|
|
||||||
static const ArchiveFileTypeEnum known_type[] = {
|
static const ArchiveFileTypeEnum known_type[] = {
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
|
|
||||||
#include "archive_favorites.h"
|
#include "archive_favorites.h"
|
||||||
#include "archive_files.h"
|
#include "archive_files.h"
|
||||||
#include "archive_apps.h"
|
#include "archive_apps.h"
|
||||||
#include "archive_browser.h"
|
#include "archive_browser.h"
|
||||||
|
|
||||||
|
#include <dialogs/dialogs.h>
|
||||||
|
|
||||||
#define ARCHIVE_FAV_FILE_BUF_LEN 32
|
#define ARCHIVE_FAV_FILE_BUF_LEN 32
|
||||||
|
|
||||||
static bool archive_favorites_read_line(File* file, FuriString* str_result) {
|
static bool archive_favorites_read_line(File* file, FuriString* str_result) {
|
||||||
@@ -337,3 +338,46 @@ void archive_favorites_save(void* context) {
|
|||||||
storage_file_free(file);
|
storage_file_free(file);
|
||||||
furi_record_close(RECORD_STORAGE);
|
furi_record_close(RECORD_STORAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void archive_favorites_handle_setting_pin_unpin(const char* app_name, const char* setting) {
|
||||||
|
DialogMessage* message = dialog_message_alloc();
|
||||||
|
|
||||||
|
FuriString* setting_path = furi_string_alloc_set_str(app_name);
|
||||||
|
if(setting) {
|
||||||
|
furi_string_push_back(setting_path, '/');
|
||||||
|
furi_string_cat_str(setting_path, setting);
|
||||||
|
}
|
||||||
|
const char* setting_path_str = furi_string_get_cstr(setting_path);
|
||||||
|
|
||||||
|
bool is_favorite = archive_is_favorite("/app:setting/%s", setting_path_str);
|
||||||
|
dialog_message_set_header(
|
||||||
|
message,
|
||||||
|
is_favorite ? "Unpin This Setting?" : "Pin This Setting?",
|
||||||
|
64,
|
||||||
|
0,
|
||||||
|
AlignCenter,
|
||||||
|
AlignTop);
|
||||||
|
dialog_message_set_text(
|
||||||
|
message,
|
||||||
|
is_favorite ? "It will no longer be\naccessible from the\nFavorites menu" :
|
||||||
|
"It will be accessible from the\nFavorites menu",
|
||||||
|
64,
|
||||||
|
32,
|
||||||
|
AlignCenter,
|
||||||
|
AlignCenter);
|
||||||
|
dialog_message_set_buttons(
|
||||||
|
message, is_favorite ? "Unpin" : "Go back", NULL, is_favorite ? "Keep pinned" : "Pin");
|
||||||
|
|
||||||
|
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
||||||
|
DialogMessageButton button = dialog_message_show(dialogs, message);
|
||||||
|
furi_record_close(RECORD_DIALOGS);
|
||||||
|
|
||||||
|
if(is_favorite && button == DialogMessageButtonLeft) {
|
||||||
|
archive_favorites_delete("/app:setting/%s", setting_path_str);
|
||||||
|
} else if(!is_favorite && button == DialogMessageButtonRight) {
|
||||||
|
archive_file_append(ARCHIVE_FAV_PATH, "/app:setting/%s\n", setting_path_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_string_free(setting_path);
|
||||||
|
dialog_message_free(message);
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,3 +12,13 @@ bool archive_is_favorite(const char* format, ...) _ATTRIBUTE((__format__(__print
|
|||||||
bool archive_favorites_rename(const char* src, const char* dst);
|
bool archive_favorites_rename(const char* src, const char* dst);
|
||||||
void archive_add_to_favorites(const char* file_path);
|
void archive_add_to_favorites(const char* file_path);
|
||||||
void archive_favorites_save(void* context);
|
void archive_favorites_save(void* context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intended to be called by settings apps to handle long presses, as well as
|
||||||
|
* internally from within the archive
|
||||||
|
*
|
||||||
|
* @param app_name name of the referring application
|
||||||
|
* @param setting name of the setting, which will be both displayed to the user
|
||||||
|
* and passed to the application as an argument upon recall
|
||||||
|
*/
|
||||||
|
void archive_favorites_handle_setting_pin_unpin(const char* app_name, const char* setting);
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ typedef enum {
|
|||||||
ArchiveFileTypeFolder,
|
ArchiveFileTypeFolder,
|
||||||
ArchiveFileTypeUnknown,
|
ArchiveFileTypeUnknown,
|
||||||
ArchiveFileTypeAppOrJs,
|
ArchiveFileTypeAppOrJs,
|
||||||
|
ArchiveFileTypeSetting,
|
||||||
ArchiveFileTypeLoading,
|
ArchiveFileTypeLoading,
|
||||||
} ArchiveFileTypeEnum;
|
} ArchiveFileTypeEnum;
|
||||||
|
|
||||||
|
|||||||
@@ -52,8 +52,23 @@ static void archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selec
|
|||||||
UNUSED(browser);
|
UNUSED(browser);
|
||||||
Loader* loader = furi_record_open(RECORD_LOADER);
|
Loader* loader = furi_record_open(RECORD_LOADER);
|
||||||
|
|
||||||
|
if(selected->type == ArchiveFileTypeSetting) {
|
||||||
|
FuriString* app_name = furi_string_alloc_set(selected->path);
|
||||||
|
furi_string_right(app_name, furi_string_search_char(app_name, '/', 1) + 1);
|
||||||
|
size_t slash = furi_string_search_char(app_name, '/', 1);
|
||||||
|
if(slash != FURI_STRING_FAILURE) {
|
||||||
|
furi_string_left(app_name, slash);
|
||||||
|
FuriString* app_args =
|
||||||
|
furi_string_alloc_set_str(furi_string_get_cstr(app_name) + slash + 1);
|
||||||
|
loader_start_with_gui_error(
|
||||||
|
loader, furi_string_get_cstr(app_name), furi_string_get_cstr(app_args));
|
||||||
|
furi_string_free(app_args);
|
||||||
|
} else {
|
||||||
|
loader_start_with_gui_error(loader, furi_string_get_cstr(app_name), NULL);
|
||||||
|
}
|
||||||
|
furi_string_free(app_name);
|
||||||
|
} else {
|
||||||
const char* app_name = archive_get_flipper_app_name(selected->type);
|
const char* app_name = archive_get_flipper_app_name(selected->type);
|
||||||
|
|
||||||
if(app_name) {
|
if(app_name) {
|
||||||
if(selected->is_app) {
|
if(selected->is_app) {
|
||||||
char* param = strrchr(furi_string_get_cstr(selected->path), '/');
|
char* param = strrchr(furi_string_get_cstr(selected->path), '/');
|
||||||
@@ -62,11 +77,13 @@ static void archive_run_in_app(ArchiveBrowserView* browser, ArchiveFile_t* selec
|
|||||||
}
|
}
|
||||||
loader_start_with_gui_error(loader, app_name, param);
|
loader_start_with_gui_error(loader, app_name, param);
|
||||||
} else {
|
} else {
|
||||||
loader_start_with_gui_error(loader, app_name, furi_string_get_cstr(selected->path));
|
loader_start_with_gui_error(
|
||||||
|
loader, app_name, furi_string_get_cstr(selected->path));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
loader_start_with_gui_error(loader, furi_string_get_cstr(selected->path), NULL);
|
loader_start_with_gui_error(loader, furi_string_get_cstr(selected->path), NULL);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
furi_record_close(RECORD_LOADER);
|
furi_record_close(RECORD_LOADER);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ static const Icon* ArchiveItemIcons[] = {
|
|||||||
[ArchiveFileTypeInfrared] = &I_ir_10px,
|
[ArchiveFileTypeInfrared] = &I_ir_10px,
|
||||||
[ArchiveFileTypeBadUsb] = &I_badusb_10px,
|
[ArchiveFileTypeBadUsb] = &I_badusb_10px,
|
||||||
[ArchiveFileTypeU2f] = &I_u2f_10px,
|
[ArchiveFileTypeU2f] = &I_u2f_10px,
|
||||||
|
[ArchiveFileTypeSetting] = &I_settings_10px,
|
||||||
[ArchiveFileTypeUpdateManifest] = &I_update_10px,
|
[ArchiveFileTypeUpdateManifest] = &I_update_10px,
|
||||||
[ArchiveFileTypeFolder] = &I_dir_10px,
|
[ArchiveFileTypeFolder] = &I_dir_10px,
|
||||||
[ArchiveFileTypeUnknown] = &I_unknown_10px,
|
[ArchiveFileTypeUnknown] = &I_unknown_10px,
|
||||||
|
|||||||
@@ -11,8 +11,12 @@ struct Submenu {
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
FuriString* label;
|
FuriString* label;
|
||||||
uint32_t index;
|
uint32_t index;
|
||||||
|
union {
|
||||||
SubmenuItemCallback callback;
|
SubmenuItemCallback callback;
|
||||||
|
SubmenuItemCallbackEx callback_ex;
|
||||||
|
};
|
||||||
void* callback_context;
|
void* callback_context;
|
||||||
|
bool has_extended_events;
|
||||||
} SubmenuItem;
|
} SubmenuItem;
|
||||||
|
|
||||||
static void SubmenuItem_init(SubmenuItem* item) {
|
static void SubmenuItem_init(SubmenuItem* item) {
|
||||||
@@ -57,7 +61,7 @@ typedef struct {
|
|||||||
|
|
||||||
static void submenu_process_up(Submenu* submenu);
|
static void submenu_process_up(Submenu* submenu);
|
||||||
static void submenu_process_down(Submenu* submenu);
|
static void submenu_process_down(Submenu* submenu);
|
||||||
static void submenu_process_ok(Submenu* submenu);
|
static void submenu_process_ok(Submenu* submenu, InputType input_type);
|
||||||
|
|
||||||
static void submenu_view_draw_callback(Canvas* canvas, void* _model) {
|
static void submenu_view_draw_callback(Canvas* canvas, void* _model) {
|
||||||
SubmenuModel* model = _model;
|
SubmenuModel* model = _model;
|
||||||
@@ -120,7 +124,10 @@ static bool submenu_view_input_callback(InputEvent* event, void* context) {
|
|||||||
furi_assert(submenu);
|
furi_assert(submenu);
|
||||||
bool consumed = false;
|
bool consumed = false;
|
||||||
|
|
||||||
if(event->type == InputTypeShort) {
|
if(event->key == InputKeyOk) {
|
||||||
|
consumed = true;
|
||||||
|
submenu_process_ok(submenu, event->type);
|
||||||
|
} else if(event->type == InputTypeShort) {
|
||||||
switch(event->key) {
|
switch(event->key) {
|
||||||
case InputKeyUp:
|
case InputKeyUp:
|
||||||
consumed = true;
|
consumed = true;
|
||||||
@@ -130,10 +137,6 @@ static bool submenu_view_input_callback(InputEvent* event, void* context) {
|
|||||||
consumed = true;
|
consumed = true;
|
||||||
submenu_process_down(submenu);
|
submenu_process_down(submenu);
|
||||||
break;
|
break;
|
||||||
case InputKeyOk:
|
|
||||||
consumed = true;
|
|
||||||
submenu_process_ok(submenu);
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -211,6 +214,31 @@ void submenu_add_item(
|
|||||||
item->index = index;
|
item->index = index;
|
||||||
item->callback = callback;
|
item->callback = callback;
|
||||||
item->callback_context = callback_context;
|
item->callback_context = callback_context;
|
||||||
|
item->has_extended_events = false;
|
||||||
|
},
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
void submenu_add_item_ex(
|
||||||
|
Submenu* submenu,
|
||||||
|
const char* label,
|
||||||
|
uint32_t index,
|
||||||
|
SubmenuItemCallbackEx callback,
|
||||||
|
void* callback_context) {
|
||||||
|
SubmenuItem* item = NULL;
|
||||||
|
furi_check(label);
|
||||||
|
furi_check(submenu);
|
||||||
|
|
||||||
|
with_view_model(
|
||||||
|
submenu->view,
|
||||||
|
SubmenuModel * model,
|
||||||
|
{
|
||||||
|
item = SubmenuItemArray_push_new(model->items);
|
||||||
|
furi_string_set_str(item->label, label);
|
||||||
|
item->index = index;
|
||||||
|
item->callback_ex = callback;
|
||||||
|
item->callback_context = callback_context;
|
||||||
|
item->has_extended_events = true;
|
||||||
},
|
},
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
@@ -357,7 +385,7 @@ void submenu_process_down(Submenu* submenu) {
|
|||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void submenu_process_ok(Submenu* submenu) {
|
void submenu_process_ok(Submenu* submenu, InputType input_type) {
|
||||||
SubmenuItem* item = NULL;
|
SubmenuItem* item = NULL;
|
||||||
|
|
||||||
with_view_model(
|
with_view_model(
|
||||||
@@ -371,8 +399,12 @@ void submenu_process_ok(Submenu* submenu) {
|
|||||||
},
|
},
|
||||||
true);
|
true);
|
||||||
|
|
||||||
if(item && item->callback) {
|
if(!item) return;
|
||||||
|
|
||||||
|
if(!item->has_extended_events && input_type == InputTypeShort && item->callback) {
|
||||||
item->callback(item->callback_context, item->index);
|
item->callback(item->callback_context, item->index);
|
||||||
|
} else if(item->has_extended_events && item->callback_ex) {
|
||||||
|
item->callback_ex(item->callback_context, input_type, item->index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ extern "C" {
|
|||||||
/** Submenu anonymous structure */
|
/** Submenu anonymous structure */
|
||||||
typedef struct Submenu Submenu;
|
typedef struct Submenu Submenu;
|
||||||
typedef void (*SubmenuItemCallback)(void* context, uint32_t index);
|
typedef void (*SubmenuItemCallback)(void* context, uint32_t index);
|
||||||
|
typedef void (*SubmenuItemCallbackEx)(void* context, InputType input_type, uint32_t index);
|
||||||
|
|
||||||
/** Allocate and initialize submenu
|
/** Allocate and initialize submenu
|
||||||
*
|
*
|
||||||
@@ -53,6 +54,22 @@ void submenu_add_item(
|
|||||||
SubmenuItemCallback callback,
|
SubmenuItemCallback callback,
|
||||||
void* callback_context);
|
void* callback_context);
|
||||||
|
|
||||||
|
/** Add item to submenu with extended press events
|
||||||
|
*
|
||||||
|
* @param submenu Submenu instance
|
||||||
|
* @param label menu item label
|
||||||
|
* @param index menu item index, used for callback, may be
|
||||||
|
* the same with other items
|
||||||
|
* @param callback menu item extended callback
|
||||||
|
* @param callback_context menu item callback context
|
||||||
|
*/
|
||||||
|
void submenu_add_item_ex(
|
||||||
|
Submenu* submenu,
|
||||||
|
const char* label,
|
||||||
|
uint32_t index,
|
||||||
|
SubmenuItemCallbackEx callback,
|
||||||
|
void* callback_context);
|
||||||
|
|
||||||
/** Change label of an existing item
|
/** Change label of an existing item
|
||||||
*
|
*
|
||||||
* @param submenu Submenu instance
|
* @param submenu Submenu instance
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include <gui/modules/submenu.h>
|
#include <gui/modules/submenu.h>
|
||||||
#include <assets_icons.h>
|
#include <assets_icons.h>
|
||||||
#include <applications.h>
|
#include <applications.h>
|
||||||
|
#include <archive/helpers/archive_favorites.h>
|
||||||
|
|
||||||
#include "loader.h"
|
#include "loader.h"
|
||||||
#include "loader_menu.h"
|
#include "loader_menu.h"
|
||||||
@@ -71,10 +72,16 @@ static void loader_menu_applications_callback(void* context, uint32_t index) {
|
|||||||
loader_menu_start(name);
|
loader_menu_start(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loader_menu_settings_menu_callback(void* context, uint32_t index) {
|
static void
|
||||||
|
loader_menu_settings_menu_callback(void* context, InputType input_type, uint32_t index) {
|
||||||
UNUSED(context);
|
UNUSED(context);
|
||||||
|
if(input_type == InputTypeShort) {
|
||||||
const char* name = FLIPPER_SETTINGS_APPS[index].name;
|
const char* name = FLIPPER_SETTINGS_APPS[index].name;
|
||||||
loader_menu_start(name);
|
loader_menu_start(name);
|
||||||
|
} else if(input_type == InputTypeLong) {
|
||||||
|
const char* name = FLIPPER_SETTINGS_APPS[index].name;
|
||||||
|
archive_favorites_handle_setting_pin_unpin(name, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loader_menu_switch_to_settings(void* context, uint32_t index) {
|
static void loader_menu_switch_to_settings(void* context, uint32_t index) {
|
||||||
@@ -128,7 +135,7 @@ static void loader_menu_build_menu(LoaderMenuApp* app, LoaderMenu* menu) {
|
|||||||
|
|
||||||
static void loader_menu_build_submenu(LoaderMenuApp* app, LoaderMenu* loader_menu) {
|
static void loader_menu_build_submenu(LoaderMenuApp* app, LoaderMenu* loader_menu) {
|
||||||
for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) {
|
for(size_t i = 0; i < FLIPPER_SETTINGS_APPS_COUNT; i++) {
|
||||||
submenu_add_item(
|
submenu_add_item_ex(
|
||||||
app->settings_menu,
|
app->settings_menu,
|
||||||
FLIPPER_SETTINGS_APPS[i].name,
|
FLIPPER_SETTINGS_APPS[i].name,
|
||||||
i,
|
i,
|
||||||
|
|||||||
@@ -1,5 +1,16 @@
|
|||||||
#include "power_settings_app.h"
|
#include "power_settings_app.h"
|
||||||
|
|
||||||
|
const SubmenuSettingsHelperDescriptor settings_helper_descriptor = {
|
||||||
|
.app_name = "Power",
|
||||||
|
.options_cnt = 3,
|
||||||
|
.options =
|
||||||
|
{
|
||||||
|
{.name = "Battery Info", .scene_id = PowerSettingsAppSceneBatteryInfo},
|
||||||
|
{.name = "Reboot", .scene_id = PowerSettingsAppSceneReboot},
|
||||||
|
{.name = "Power OFF", .scene_id = PowerSettingsAppScenePowerOff},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static bool power_settings_custom_event_callback(void* context, uint32_t event) {
|
static bool power_settings_custom_event_callback(void* context, uint32_t event) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
PowerSettingsApp* app = context;
|
PowerSettingsApp* app = context;
|
||||||
@@ -18,7 +29,7 @@ static void power_settings_tick_event_callback(void* context) {
|
|||||||
scene_manager_handle_tick_event(app->scene_manager);
|
scene_manager_handle_tick_event(app->scene_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
PowerSettingsApp* power_settings_app_alloc(uint32_t first_scene) {
|
PowerSettingsApp* power_settings_app_alloc(void) {
|
||||||
PowerSettingsApp* app = malloc(sizeof(PowerSettingsApp));
|
PowerSettingsApp* app = malloc(sizeof(PowerSettingsApp));
|
||||||
|
|
||||||
// Records
|
// Records
|
||||||
@@ -50,13 +61,23 @@ PowerSettingsApp* power_settings_app_alloc(uint32_t first_scene) {
|
|||||||
view_dispatcher_add_view(
|
view_dispatcher_add_view(
|
||||||
app->view_dispatcher, PowerSettingsAppViewDialog, dialog_ex_get_view(app->dialog));
|
app->view_dispatcher, PowerSettingsAppViewDialog, dialog_ex_get_view(app->dialog));
|
||||||
|
|
||||||
// Set first scene
|
// Helper
|
||||||
scene_manager_next_scene(app->scene_manager, first_scene);
|
app->settings_helper = submenu_settings_helpers_alloc(&settings_helper_descriptor);
|
||||||
|
submenu_settings_helpers_assign_objects(
|
||||||
|
app->settings_helper,
|
||||||
|
app->view_dispatcher,
|
||||||
|
app->scene_manager,
|
||||||
|
app->submenu,
|
||||||
|
PowerSettingsAppViewSubmenu,
|
||||||
|
PowerSettingsAppSceneStart);
|
||||||
|
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
void power_settings_app_free(PowerSettingsApp* app) {
|
void power_settings_app_free(PowerSettingsApp* app) {
|
||||||
furi_assert(app);
|
furi_assert(app);
|
||||||
|
// Helper
|
||||||
|
submenu_settings_helpers_free(app->settings_helper);
|
||||||
// Views
|
// Views
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewBatteryInfo);
|
view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewBatteryInfo);
|
||||||
battery_info_free(app->batery_info);
|
battery_info_free(app->batery_info);
|
||||||
@@ -74,11 +95,14 @@ void power_settings_app_free(PowerSettingsApp* app) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int32_t power_settings_app(void* p) {
|
int32_t power_settings_app(void* p) {
|
||||||
|
PowerSettingsApp* app = power_settings_app_alloc();
|
||||||
|
if(!submenu_settings_helpers_app_start(app->settings_helper, p)) {
|
||||||
uint32_t first_scene = PowerSettingsAppSceneStart;
|
uint32_t first_scene = PowerSettingsAppSceneStart;
|
||||||
if(p && strlen(p) && !strcmp(p, "off")) {
|
if(p && strlen(p) && !strcmp(p, "off")) {
|
||||||
first_scene = PowerSettingsAppScenePowerOff;
|
first_scene = PowerSettingsAppScenePowerOff;
|
||||||
}
|
}
|
||||||
PowerSettingsApp* app = power_settings_app_alloc(first_scene);
|
scene_manager_next_scene(app->scene_manager, first_scene);
|
||||||
|
}
|
||||||
view_dispatcher_run(app->view_dispatcher);
|
view_dispatcher_run(app->view_dispatcher);
|
||||||
power_settings_app_free(app);
|
power_settings_app_free(app);
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -14,6 +14,8 @@
|
|||||||
|
|
||||||
#include "scenes/power_settings_scene.h"
|
#include "scenes/power_settings_scene.h"
|
||||||
|
|
||||||
|
#include <settings_helpers/submenu_based.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
Power* power;
|
Power* power;
|
||||||
Gui* gui;
|
Gui* gui;
|
||||||
@@ -23,6 +25,7 @@ typedef struct {
|
|||||||
Submenu* submenu;
|
Submenu* submenu;
|
||||||
DialogEx* dialog;
|
DialogEx* dialog;
|
||||||
PowerInfo info;
|
PowerInfo info;
|
||||||
|
SubmenuSettingsHelper* settings_helper;
|
||||||
} PowerSettingsApp;
|
} PowerSettingsApp;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
@@ -1,64 +1,16 @@
|
|||||||
#include "../power_settings_app.h"
|
#include "../power_settings_app.h"
|
||||||
|
|
||||||
enum PowerSettingsSubmenuIndex {
|
|
||||||
PowerSettingsSubmenuIndexBatteryInfo,
|
|
||||||
PowerSettingsSubmenuIndexReboot,
|
|
||||||
PowerSettingsSubmenuIndexOff,
|
|
||||||
};
|
|
||||||
|
|
||||||
static void power_settings_scene_start_submenu_callback(void* context, uint32_t index) {
|
|
||||||
furi_assert(context);
|
|
||||||
PowerSettingsApp* app = context;
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void power_settings_scene_start_on_enter(void* context) {
|
void power_settings_scene_start_on_enter(void* context) {
|
||||||
PowerSettingsApp* app = context;
|
PowerSettingsApp* app = context;
|
||||||
Submenu* submenu = app->submenu;
|
submenu_settings_helpers_scene_enter(app->settings_helper);
|
||||||
|
|
||||||
submenu_add_item(
|
|
||||||
submenu,
|
|
||||||
"Battery Info",
|
|
||||||
PowerSettingsSubmenuIndexBatteryInfo,
|
|
||||||
power_settings_scene_start_submenu_callback,
|
|
||||||
app);
|
|
||||||
submenu_add_item(
|
|
||||||
submenu,
|
|
||||||
"Reboot",
|
|
||||||
PowerSettingsSubmenuIndexReboot,
|
|
||||||
power_settings_scene_start_submenu_callback,
|
|
||||||
app);
|
|
||||||
submenu_add_item(
|
|
||||||
submenu,
|
|
||||||
"Power OFF",
|
|
||||||
PowerSettingsSubmenuIndexOff,
|
|
||||||
power_settings_scene_start_submenu_callback,
|
|
||||||
app);
|
|
||||||
submenu_set_selected_item(
|
|
||||||
submenu, scene_manager_get_scene_state(app->scene_manager, PowerSettingsAppSceneStart));
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, PowerSettingsAppViewSubmenu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool power_settings_scene_start_on_event(void* context, SceneManagerEvent event) {
|
bool power_settings_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||||
PowerSettingsApp* app = context;
|
PowerSettingsApp* app = context;
|
||||||
bool consumed = false;
|
return submenu_settings_helpers_scene_event(app->settings_helper, event);
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
if(event.event == PowerSettingsSubmenuIndexBatteryInfo) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, PowerSettingsAppSceneBatteryInfo);
|
|
||||||
} else if(event.event == PowerSettingsSubmenuIndexReboot) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, PowerSettingsAppSceneReboot);
|
|
||||||
} else if(event.event == PowerSettingsSubmenuIndexOff) {
|
|
||||||
scene_manager_next_scene(app->scene_manager, PowerSettingsAppScenePowerOff);
|
|
||||||
}
|
|
||||||
scene_manager_set_scene_state(app->scene_manager, PowerSettingsAppSceneStart, event.event);
|
|
||||||
consumed = true;
|
|
||||||
}
|
|
||||||
return consumed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void power_settings_scene_start_on_exit(void* context) {
|
void power_settings_scene_start_on_exit(void* context) {
|
||||||
PowerSettingsApp* app = context;
|
PowerSettingsApp* app = context;
|
||||||
submenu_reset(app->submenu);
|
submenu_settings_helpers_scene_exit(app->settings_helper);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,131 +1,20 @@
|
|||||||
#include "../storage_settings.h"
|
#include "../storage_settings.h"
|
||||||
|
|
||||||
enum StorageSettingsStartSubmenuIndex {
|
|
||||||
StorageSettingsStartSubmenuIndexInternalInfo,
|
|
||||||
StorageSettingsStartSubmenuIndexSDInfo,
|
|
||||||
StorageSettingsStartSubmenuIndexUnmount,
|
|
||||||
StorageSettingsStartSubmenuIndexFormat,
|
|
||||||
StorageSettingsStartSubmenuIndexBenchy,
|
|
||||||
StorageSettingsStartSubmenuIndexFactoryReset
|
|
||||||
};
|
|
||||||
|
|
||||||
static void storage_settings_scene_start_submenu_callback(void* context, uint32_t index) {
|
|
||||||
StorageSettings* app = context;
|
|
||||||
|
|
||||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
|
||||||
}
|
|
||||||
|
|
||||||
void storage_settings_scene_start_on_enter(void* context) {
|
void storage_settings_scene_start_on_enter(void* context) {
|
||||||
StorageSettings* app = context;
|
StorageSettings* app = context;
|
||||||
Submenu* submenu = app->submenu;
|
|
||||||
|
|
||||||
submenu_add_item(
|
|
||||||
submenu,
|
|
||||||
"About Internal Storage",
|
|
||||||
StorageSettingsStartSubmenuIndexInternalInfo,
|
|
||||||
storage_settings_scene_start_submenu_callback,
|
|
||||||
app);
|
|
||||||
submenu_add_item(
|
|
||||||
submenu,
|
|
||||||
"About SD Card",
|
|
||||||
StorageSettingsStartSubmenuIndexSDInfo,
|
|
||||||
storage_settings_scene_start_submenu_callback,
|
|
||||||
app);
|
|
||||||
|
|
||||||
FS_Error sd_status = storage_sd_status(app->fs_api);
|
FS_Error sd_status = storage_sd_status(app->fs_api);
|
||||||
if(sd_status != FSE_OK) {
|
app->helper_descriptor->options[STORAGE_SETTINGS_MOUNT_INDEX].name =
|
||||||
submenu_add_item(
|
(sd_status != FSE_OK) ? "Mount SD Card" : "Unmount SD Card";
|
||||||
submenu,
|
submenu_settings_helpers_scene_enter(app->settings_helper);
|
||||||
"Mount SD Card",
|
|
||||||
StorageSettingsStartSubmenuIndexUnmount,
|
|
||||||
storage_settings_scene_start_submenu_callback,
|
|
||||||
app);
|
|
||||||
} else {
|
|
||||||
submenu_add_item(
|
|
||||||
submenu,
|
|
||||||
"Unmount SD Card",
|
|
||||||
StorageSettingsStartSubmenuIndexUnmount,
|
|
||||||
storage_settings_scene_start_submenu_callback,
|
|
||||||
app);
|
|
||||||
}
|
|
||||||
|
|
||||||
submenu_add_item(
|
|
||||||
submenu,
|
|
||||||
"Format SD Card",
|
|
||||||
StorageSettingsStartSubmenuIndexFormat,
|
|
||||||
storage_settings_scene_start_submenu_callback,
|
|
||||||
app);
|
|
||||||
submenu_add_item(
|
|
||||||
submenu,
|
|
||||||
"Benchmark SD Card",
|
|
||||||
StorageSettingsStartSubmenuIndexBenchy,
|
|
||||||
storage_settings_scene_start_submenu_callback,
|
|
||||||
app);
|
|
||||||
submenu_add_item(
|
|
||||||
submenu,
|
|
||||||
"Factory Reset",
|
|
||||||
StorageSettingsStartSubmenuIndexFactoryReset,
|
|
||||||
storage_settings_scene_start_submenu_callback,
|
|
||||||
app);
|
|
||||||
|
|
||||||
submenu_set_selected_item(
|
|
||||||
submenu, scene_manager_get_scene_state(app->scene_manager, StorageSettingsStart));
|
|
||||||
|
|
||||||
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewSubmenu);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool storage_settings_scene_start_on_event(void* context, SceneManagerEvent event) {
|
bool storage_settings_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||||
StorageSettings* app = context;
|
StorageSettings* app = context;
|
||||||
bool consumed = false;
|
return submenu_settings_helpers_scene_event(app->settings_helper, event);
|
||||||
|
|
||||||
if(event.type == SceneManagerEventTypeCustom) {
|
|
||||||
switch(event.event) {
|
|
||||||
case StorageSettingsStartSubmenuIndexSDInfo:
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
app->scene_manager, StorageSettingsStart, StorageSettingsStartSubmenuIndexSDInfo);
|
|
||||||
scene_manager_next_scene(app->scene_manager, StorageSettingsSDInfo);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
case StorageSettingsStartSubmenuIndexInternalInfo:
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
app->scene_manager,
|
|
||||||
StorageSettingsStart,
|
|
||||||
StorageSettingsStartSubmenuIndexInternalInfo);
|
|
||||||
scene_manager_next_scene(app->scene_manager, StorageSettingsInternalInfo);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
case StorageSettingsStartSubmenuIndexUnmount:
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
app->scene_manager, StorageSettingsStart, StorageSettingsStartSubmenuIndexUnmount);
|
|
||||||
scene_manager_next_scene(app->scene_manager, StorageSettingsUnmountConfirm);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
case StorageSettingsStartSubmenuIndexFormat:
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
app->scene_manager, StorageSettingsStart, StorageSettingsStartSubmenuIndexFormat);
|
|
||||||
scene_manager_next_scene(app->scene_manager, StorageSettingsFormatConfirm);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
case StorageSettingsStartSubmenuIndexBenchy:
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
app->scene_manager, StorageSettingsStart, StorageSettingsStartSubmenuIndexBenchy);
|
|
||||||
scene_manager_next_scene(app->scene_manager, StorageSettingsBenchmarkConfirm);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
case StorageSettingsStartSubmenuIndexFactoryReset:
|
|
||||||
scene_manager_set_scene_state(
|
|
||||||
app->scene_manager,
|
|
||||||
StorageSettingsStart,
|
|
||||||
StorageSettingsStartSubmenuIndexFactoryReset);
|
|
||||||
scene_manager_next_scene(app->scene_manager, StorageSettingsFactoryReset);
|
|
||||||
consumed = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return consumed;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void storage_settings_scene_start_on_exit(void* context) {
|
void storage_settings_scene_start_on_exit(void* context) {
|
||||||
StorageSettings* app = context;
|
StorageSettings* app = context;
|
||||||
submenu_reset(app->submenu);
|
submenu_settings_helpers_scene_exit(app->settings_helper);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,19 @@
|
|||||||
#include "storage_settings.h"
|
#include "storage_settings.h"
|
||||||
|
|
||||||
|
const SubmenuSettingsHelperDescriptor descriptor_template = {
|
||||||
|
.app_name = "Storage",
|
||||||
|
.options_cnt = 6,
|
||||||
|
.options =
|
||||||
|
{
|
||||||
|
{.name = "About Internal Storage", .scene_id = StorageSettingsSDInfo},
|
||||||
|
{.name = "About SD Card", .scene_id = StorageSettingsInternalInfo},
|
||||||
|
{.name = "Unmount SD Card", .scene_id = StorageSettingsUnmountConfirm},
|
||||||
|
{.name = "Format SD Card", .scene_id = StorageSettingsFormatConfirm},
|
||||||
|
{.name = "Benchmark SD Card", .scene_id = StorageSettingsBenchmarkConfirm},
|
||||||
|
{.name = "Factory Reset", .scene_id = StorageSettingsFactoryReset},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
static bool storage_settings_custom_event_callback(void* context, uint32_t event) {
|
static bool storage_settings_custom_event_callback(void* context, uint32_t event) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
StorageSettings* app = context;
|
StorageSettings* app = context;
|
||||||
@@ -40,12 +54,27 @@ static StorageSettings* storage_settings_alloc(void) {
|
|||||||
view_dispatcher_add_view(
|
view_dispatcher_add_view(
|
||||||
app->view_dispatcher, StorageSettingsViewDialogEx, dialog_ex_get_view(app->dialog_ex));
|
app->view_dispatcher, StorageSettingsViewDialogEx, dialog_ex_get_view(app->dialog_ex));
|
||||||
|
|
||||||
scene_manager_next_scene(app->scene_manager, StorageSettingsStart);
|
size_t descriptor_size =
|
||||||
|
sizeof(SubmenuSettingsHelperDescriptor) +
|
||||||
|
(descriptor_template.options_cnt * sizeof(SubmenuSettingsHelperOption));
|
||||||
|
app->helper_descriptor = malloc(descriptor_size);
|
||||||
|
memcpy(app->helper_descriptor, &descriptor_template, descriptor_size);
|
||||||
|
app->settings_helper = submenu_settings_helpers_alloc(app->helper_descriptor);
|
||||||
|
submenu_settings_helpers_assign_objects(
|
||||||
|
app->settings_helper,
|
||||||
|
app->view_dispatcher,
|
||||||
|
app->scene_manager,
|
||||||
|
app->submenu,
|
||||||
|
StorageSettingsViewSubmenu,
|
||||||
|
StorageSettingsStart);
|
||||||
|
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void storage_settings_free(StorageSettings* app) {
|
static void storage_settings_free(StorageSettings* app) {
|
||||||
|
submenu_settings_helpers_free(app->settings_helper);
|
||||||
|
free(app->helper_descriptor);
|
||||||
|
|
||||||
view_dispatcher_remove_view(app->view_dispatcher, StorageSettingsViewSubmenu);
|
view_dispatcher_remove_view(app->view_dispatcher, StorageSettingsViewSubmenu);
|
||||||
submenu_free(app->submenu);
|
submenu_free(app->submenu);
|
||||||
|
|
||||||
@@ -68,6 +97,10 @@ int32_t storage_settings_app(void* p) {
|
|||||||
UNUSED(p);
|
UNUSED(p);
|
||||||
StorageSettings* app = storage_settings_alloc();
|
StorageSettings* app = storage_settings_alloc();
|
||||||
|
|
||||||
|
if(!submenu_settings_helpers_app_start(app->settings_helper, p)) {
|
||||||
|
scene_manager_next_scene(app->scene_manager, StorageSettingsStart);
|
||||||
|
}
|
||||||
|
|
||||||
view_dispatcher_run(app->view_dispatcher);
|
view_dispatcher_run(app->view_dispatcher);
|
||||||
|
|
||||||
storage_settings_free(app);
|
storage_settings_free(app);
|
||||||
|
|||||||
@@ -16,6 +16,10 @@
|
|||||||
|
|
||||||
#include "scenes/storage_settings_scene.h"
|
#include "scenes/storage_settings_scene.h"
|
||||||
|
|
||||||
|
#include <settings_helpers/submenu_based.h>
|
||||||
|
|
||||||
|
#define STORAGE_SETTINGS_MOUNT_INDEX 2
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
@@ -36,6 +40,10 @@ typedef struct {
|
|||||||
|
|
||||||
// text
|
// text
|
||||||
FuriString* text_string;
|
FuriString* text_string;
|
||||||
|
|
||||||
|
// helpers
|
||||||
|
SubmenuSettingsHelperDescriptor* helper_descriptor;
|
||||||
|
SubmenuSettingsHelper* settings_helper;
|
||||||
} StorageSettings;
|
} StorageSettings;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
|||||||
BIN
assets/icons/Archive/settings_10px.png
Normal file
BIN
assets/icons/Archive/settings_10px.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 96 B |
@@ -76,6 +76,7 @@ FIRMWARE_APPS = {
|
|||||||
"radio_device_cc1101_ext",
|
"radio_device_cc1101_ext",
|
||||||
"unit_tests",
|
"unit_tests",
|
||||||
"js_app",
|
"js_app",
|
||||||
|
"archive",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
103
lib/toolbox/settings_helpers/submenu_based.c
Normal file
103
lib/toolbox/settings_helpers/submenu_based.c
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
#include "submenu_based.h"
|
||||||
|
#include <archive/helpers/archive_favorites.h>
|
||||||
|
|
||||||
|
struct SubmenuSettingsHelper {
|
||||||
|
const SubmenuSettingsHelperDescriptor* descriptor;
|
||||||
|
ViewDispatcher* view_dispatcher;
|
||||||
|
SceneManager* scene_manager;
|
||||||
|
Submenu* submenu;
|
||||||
|
uint32_t submenu_view_id;
|
||||||
|
uint32_t main_scene_id;
|
||||||
|
};
|
||||||
|
|
||||||
|
SubmenuSettingsHelper*
|
||||||
|
submenu_settings_helpers_alloc(const SubmenuSettingsHelperDescriptor* descriptor) {
|
||||||
|
furi_check(descriptor);
|
||||||
|
SubmenuSettingsHelper* helper = malloc(sizeof(SubmenuSettingsHelper));
|
||||||
|
helper->descriptor = descriptor;
|
||||||
|
return helper;
|
||||||
|
}
|
||||||
|
|
||||||
|
void submenu_settings_helpers_assign_objects(
|
||||||
|
SubmenuSettingsHelper* helper,
|
||||||
|
ViewDispatcher* view_dispatcher,
|
||||||
|
SceneManager* scene_manager,
|
||||||
|
Submenu* submenu,
|
||||||
|
uint32_t submenu_view_id,
|
||||||
|
uint32_t main_scene_id) {
|
||||||
|
furi_check(helper);
|
||||||
|
furi_check(view_dispatcher);
|
||||||
|
furi_check(scene_manager);
|
||||||
|
furi_check(submenu);
|
||||||
|
helper->view_dispatcher = view_dispatcher;
|
||||||
|
helper->scene_manager = scene_manager;
|
||||||
|
helper->submenu = submenu;
|
||||||
|
helper->submenu_view_id = submenu_view_id;
|
||||||
|
helper->main_scene_id = main_scene_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
void submenu_settings_helpers_free(SubmenuSettingsHelper* helper) {
|
||||||
|
free(helper);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool submenu_settings_helpers_app_start(SubmenuSettingsHelper* helper, void* arg) {
|
||||||
|
furi_check(helper);
|
||||||
|
if(!arg) return false;
|
||||||
|
|
||||||
|
const char* option = arg;
|
||||||
|
for(size_t i = 0; i < helper->descriptor->options_cnt; i++) {
|
||||||
|
if(strcmp(helper->descriptor->options[i].name, option) == 0) {
|
||||||
|
scene_manager_next_scene(
|
||||||
|
helper->scene_manager, helper->descriptor->options[i].scene_id);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
submenu_settings_helpers_callback(void* context, InputType input_type, uint32_t index) {
|
||||||
|
SubmenuSettingsHelper* helper = context;
|
||||||
|
if(input_type == InputTypeShort) {
|
||||||
|
view_dispatcher_send_custom_event(helper->view_dispatcher, index);
|
||||||
|
} else if(input_type == InputTypeLong) {
|
||||||
|
archive_favorites_handle_setting_pin_unpin(
|
||||||
|
helper->descriptor->app_name, helper->descriptor->options[index].name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void submenu_settings_helpers_scene_enter(SubmenuSettingsHelper* helper) {
|
||||||
|
furi_check(helper);
|
||||||
|
for(size_t i = 0; i < helper->descriptor->options_cnt; i++) {
|
||||||
|
submenu_add_item_ex(
|
||||||
|
helper->submenu,
|
||||||
|
helper->descriptor->options[i].name,
|
||||||
|
i,
|
||||||
|
submenu_settings_helpers_callback,
|
||||||
|
helper);
|
||||||
|
}
|
||||||
|
|
||||||
|
submenu_set_selected_item(
|
||||||
|
helper->submenu,
|
||||||
|
scene_manager_get_scene_state(helper->scene_manager, helper->main_scene_id));
|
||||||
|
view_dispatcher_switch_to_view(helper->view_dispatcher, helper->submenu_view_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool submenu_settings_helpers_scene_event(SubmenuSettingsHelper* helper, SceneManagerEvent event) {
|
||||||
|
furi_check(helper);
|
||||||
|
|
||||||
|
if(event.type == SceneManagerEventTypeCustom) {
|
||||||
|
scene_manager_next_scene(
|
||||||
|
helper->scene_manager, helper->descriptor->options[event.event].scene_id);
|
||||||
|
scene_manager_set_scene_state(helper->scene_manager, helper->main_scene_id, event.event);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void submenu_settings_helpers_scene_exit(SubmenuSettingsHelper* helper) {
|
||||||
|
furi_check(helper);
|
||||||
|
submenu_reset(helper->submenu);
|
||||||
|
}
|
||||||
89
lib/toolbox/settings_helpers/submenu_based.h
Normal file
89
lib/toolbox/settings_helpers/submenu_based.h
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
#include <gui/modules/submenu.h>
|
||||||
|
#include <gui/view_dispatcher.h>
|
||||||
|
#include <gui/scene_manager.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef void (*SubmenuSettingsHelpherCallback)(void* context, uint32_t index);
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char* name;
|
||||||
|
uint32_t scene_id;
|
||||||
|
} SubmenuSettingsHelperOption;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char* app_name;
|
||||||
|
size_t options_cnt;
|
||||||
|
SubmenuSettingsHelperOption options[];
|
||||||
|
} SubmenuSettingsHelperDescriptor;
|
||||||
|
|
||||||
|
typedef struct SubmenuSettingsHelper SubmenuSettingsHelper;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Allocates a submenu-based settings helper
|
||||||
|
* @param descriptor settings descriptor
|
||||||
|
*/
|
||||||
|
SubmenuSettingsHelper*
|
||||||
|
submenu_settings_helpers_alloc(const SubmenuSettingsHelperDescriptor* descriptor);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Assigns dynamic objects to the submenu-based settings helper
|
||||||
|
* @param helper helper object
|
||||||
|
* @param view_dispatcher ViewDispatcher
|
||||||
|
* @param scene_manager SceneManager
|
||||||
|
* @param submenu Submenu
|
||||||
|
* @param submenu_view_id Submenu view id in the ViewDispatcher
|
||||||
|
* @param main_scene_id Main scene id in the SceneManager
|
||||||
|
*/
|
||||||
|
void submenu_settings_helpers_assign_objects(
|
||||||
|
SubmenuSettingsHelper* helper,
|
||||||
|
ViewDispatcher* view_dispatcher,
|
||||||
|
SceneManager* scene_manager,
|
||||||
|
Submenu* submenu,
|
||||||
|
uint32_t submenu_view_id,
|
||||||
|
uint32_t main_scene_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Frees a submenu-based settings helper
|
||||||
|
* @param helper helper object
|
||||||
|
*/
|
||||||
|
void submenu_settings_helpers_free(SubmenuSettingsHelper* helper);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief App start callback for the submenu-based settings helper
|
||||||
|
*
|
||||||
|
* If an argument containing one of the options was provided, launches the
|
||||||
|
* corresponding scene.
|
||||||
|
*
|
||||||
|
* @param helper helper object
|
||||||
|
* @param arg app argument, may be NULL
|
||||||
|
* @returns true if a setting name was provided in the argument, false if normal
|
||||||
|
* app operation shall commence
|
||||||
|
*/
|
||||||
|
bool submenu_settings_helpers_app_start(SubmenuSettingsHelper* helper, void* arg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Main scene enter callback for the submenu-based settings helper
|
||||||
|
* @param helper helper object
|
||||||
|
*/
|
||||||
|
void submenu_settings_helpers_scene_enter(SubmenuSettingsHelper* helper);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Main scene event callback for the submenu-based settings helper
|
||||||
|
* @param helper helper object
|
||||||
|
* @param event event data
|
||||||
|
* @returns true if the event was consumed, false otherwise
|
||||||
|
*/
|
||||||
|
bool submenu_settings_helpers_scene_event(SubmenuSettingsHelper* helper, SceneManagerEvent event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Main scene exit callback for the submenu-based settings helper
|
||||||
|
* @param helper helper object
|
||||||
|
*/
|
||||||
|
void submenu_settings_helpers_scene_exit(SubmenuSettingsHelper* helper);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
@@ -2726,6 +2726,7 @@ Function,-,strverscmp,int,"const char*, const char*"
|
|||||||
Function,-,strxfrm,size_t,"char*, const char*, size_t"
|
Function,-,strxfrm,size_t,"char*, const char*, size_t"
|
||||||
Function,-,strxfrm_l,size_t,"char*, const char*, size_t, locale_t"
|
Function,-,strxfrm_l,size_t,"char*, const char*, size_t, locale_t"
|
||||||
Function,+,submenu_add_item,void,"Submenu*, const char*, uint32_t, SubmenuItemCallback, void*"
|
Function,+,submenu_add_item,void,"Submenu*, const char*, uint32_t, SubmenuItemCallback, void*"
|
||||||
|
Function,+,submenu_add_item_ex,void,"Submenu*, const char*, uint32_t, SubmenuItemCallbackEx, void*"
|
||||||
Function,+,submenu_alloc,Submenu*,
|
Function,+,submenu_alloc,Submenu*,
|
||||||
Function,+,submenu_change_item_label,void,"Submenu*, uint32_t, const char*"
|
Function,+,submenu_change_item_label,void,"Submenu*, uint32_t, const char*"
|
||||||
Function,+,submenu_free,void,Submenu*
|
Function,+,submenu_free,void,Submenu*
|
||||||
|
|||||||
|
@@ -3575,6 +3575,7 @@ Function,+,subghz_worker_set_pair_callback,void,"SubGhzWorker*, SubGhzWorkerPair
|
|||||||
Function,+,subghz_worker_start,void,SubGhzWorker*
|
Function,+,subghz_worker_start,void,SubGhzWorker*
|
||||||
Function,+,subghz_worker_stop,void,SubGhzWorker*
|
Function,+,subghz_worker_stop,void,SubGhzWorker*
|
||||||
Function,+,submenu_add_item,void,"Submenu*, const char*, uint32_t, SubmenuItemCallback, void*"
|
Function,+,submenu_add_item,void,"Submenu*, const char*, uint32_t, SubmenuItemCallback, void*"
|
||||||
|
Function,+,submenu_add_item_ex,void,"Submenu*, const char*, uint32_t, SubmenuItemCallbackEx, void*"
|
||||||
Function,+,submenu_alloc,Submenu*,
|
Function,+,submenu_alloc,Submenu*,
|
||||||
Function,+,submenu_change_item_label,void,"Submenu*, uint32_t, const char*"
|
Function,+,submenu_change_item_label,void,"Submenu*, uint32_t, const char*"
|
||||||
Function,+,submenu_free,void,Submenu*
|
Function,+,submenu_free,void,Submenu*
|
||||||
|
|||||||
|
Reference in New Issue
Block a user