mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-11 06:09:08 -07:00
Merge branch 'ofw-dev' into dev
This commit is contained in:
@@ -89,6 +89,14 @@ void cli_command_help(Cli* cli, FuriString* args, void* context) {
|
||||
}
|
||||
}
|
||||
|
||||
void cli_command_uptime(Cli* cli, FuriString* args, void* context) {
|
||||
UNUSED(cli);
|
||||
UNUSED(args);
|
||||
UNUSED(context);
|
||||
uint32_t uptime = furi_get_tick() / furi_kernel_get_tick_frequency();
|
||||
printf("Uptime: %luh%lum%lus", uptime / 60 / 60, uptime / 60 % 60, uptime % 60);
|
||||
}
|
||||
|
||||
void cli_command_date(Cli* cli, FuriString* args, void* context) {
|
||||
UNUSED(cli);
|
||||
UNUSED(context);
|
||||
@@ -462,6 +470,7 @@ void cli_commands_init(Cli* cli) {
|
||||
cli_add_command(cli, "?", CliCommandFlagParallelSafe, cli_command_help, NULL);
|
||||
cli_add_command(cli, "help", CliCommandFlagParallelSafe, cli_command_help, NULL);
|
||||
|
||||
cli_add_command(cli, "uptime", CliCommandFlagDefault, cli_command_uptime, NULL);
|
||||
cli_add_command(cli, "date", CliCommandFlagParallelSafe, cli_command_date, NULL);
|
||||
cli_add_command(cli, "log", CliCommandFlagParallelSafe, cli_command_log, NULL);
|
||||
cli_add_command(cli, "sysctl", CliCommandFlagDefault, cli_command_sysctl, NULL);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <toolbox/saved_struct.h>
|
||||
#include <storage/storage.h>
|
||||
|
||||
#define DESKTOP_SETTINGS_VER (11)
|
||||
#define DESKTOP_SETTINGS_VER (12)
|
||||
|
||||
#define DESKTOP_SETTINGS_PATH INT_PATH(DESKTOP_SETTINGS_FILE_NAME)
|
||||
#define DESKTOP_SETTINGS_MAGIC (0x17)
|
||||
@@ -49,7 +49,6 @@ typedef struct {
|
||||
} PinCode;
|
||||
|
||||
typedef struct {
|
||||
bool is_external;
|
||||
char name_or_path[MAX_APP_LENGTH];
|
||||
} FavoriteApp;
|
||||
|
||||
|
||||
@@ -14,8 +14,6 @@ void desktop_scene_debug_callback(DesktopEvent event, void* context) {
|
||||
void desktop_scene_debug_on_enter(void* context) {
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
|
||||
desktop_debug_get_dolphin_data(desktop->debug_view);
|
||||
|
||||
desktop_debug_set_callback(desktop->debug_view, desktop_scene_debug_callback, desktop);
|
||||
view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewIdDebug);
|
||||
}
|
||||
@@ -32,24 +30,6 @@ bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) {
|
||||
dolphin_flush(dolphin);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
case DesktopDebugEventDeed:
|
||||
dolphin_deed(DolphinDeedTestRight);
|
||||
desktop_debug_get_dolphin_data(desktop->debug_view);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
case DesktopDebugEventWrongDeed:
|
||||
dolphin_deed(DolphinDeedTestLeft);
|
||||
desktop_debug_get_dolphin_data(desktop->debug_view);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
case DesktopDebugEventSaveState:
|
||||
dolphin_flush(dolphin);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -60,6 +40,5 @@ bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) {
|
||||
}
|
||||
|
||||
void desktop_scene_debug_on_exit(void* context) {
|
||||
Desktop* desktop = (Desktop*)context;
|
||||
desktop_debug_reset_screen_idx(desktop->debug_view);
|
||||
UNUSED(context);
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ static void desktop_scene_main_open_app_or_profile(Desktop* desktop, const char*
|
||||
static void desktop_scene_main_start_favorite(Desktop* desktop, FavoriteApp* application) {
|
||||
if(strlen(application->name_or_path) > 2) {
|
||||
loader_start_with_gui_error(desktop->loader, application->name_or_path, NULL);
|
||||
} else if((strlen(application->name_or_path) < 2) && (application->is_external == true)) {
|
||||
} else if(strlen(application->name_or_path) < 2) {
|
||||
loader_start(desktop->loader, LOADER_APPLICATIONS_NAME, NULL, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,20 +18,26 @@ void desktop_debug_set_callback(
|
||||
}
|
||||
|
||||
void desktop_debug_render(Canvas* canvas, void* model) {
|
||||
UNUSED(model);
|
||||
canvas_clear(canvas);
|
||||
DesktopDebugViewModel* m = model;
|
||||
const Version* ver;
|
||||
char buffer[64];
|
||||
|
||||
static const char* headers[] = {"Device Info:", "Dolphin Info:"};
|
||||
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
canvas_draw_str_aligned(
|
||||
canvas, 64, 1 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignTop, headers[m->screen]);
|
||||
|
||||
uint32_t uptime = furi_get_tick() / furi_kernel_get_tick_frequency();
|
||||
snprintf(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"Uptime: %luh%lum%lus",
|
||||
uptime / 60 / 60,
|
||||
uptime / 60 % 60,
|
||||
uptime % 60);
|
||||
canvas_draw_str_aligned(canvas, 64, 1 + STATUS_BAR_Y_SHIFT, AlignCenter, AlignTop, buffer);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
|
||||
if(m->screen != DesktopViewStatsMeta) {
|
||||
// Hardware version
|
||||
const char* my_name = furi_hal_version_get_name_ptr();
|
||||
snprintf(
|
||||
@@ -46,67 +52,36 @@ void desktop_debug_render(Canvas* canvas, void* model) {
|
||||
my_name ? my_name : "Unknown");
|
||||
canvas_draw_str(canvas, 0, 19 + STATUS_BAR_Y_SHIFT, buffer);
|
||||
|
||||
ver = furi_hal_version_get_firmware_version();
|
||||
const BleGlueC2Info* c2_ver = NULL;
|
||||
ver = furi_hal_version_get_firmware_version();
|
||||
const BleGlueC2Info* c2_ver = NULL;
|
||||
#ifdef SRV_BT
|
||||
c2_ver = ble_glue_get_c2_info();
|
||||
c2_ver = ble_glue_get_c2_info();
|
||||
#endif
|
||||
if(!ver) { //-V1051
|
||||
canvas_draw_str(canvas, 0, 30 + STATUS_BAR_Y_SHIFT, "No info");
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"%s [%s]",
|
||||
version_get_version(ver),
|
||||
version_get_builddate(ver));
|
||||
canvas_draw_str(canvas, 0, 30 + STATUS_BAR_Y_SHIFT, buffer);
|
||||
|
||||
uint16_t api_major, api_minor;
|
||||
furi_hal_info_get_api_version(&api_major, &api_minor);
|
||||
snprintf(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"%s%s [%d.%d] %s",
|
||||
version_get_dirty_flag(ver) ? "[!] " : "",
|
||||
version_get_githash(ver),
|
||||
api_major,
|
||||
api_minor,
|
||||
c2_ver ? c2_ver->StackTypeString : "<none>");
|
||||
canvas_draw_str(canvas, 0, 40 + STATUS_BAR_Y_SHIFT, buffer);
|
||||
|
||||
snprintf(
|
||||
buffer, sizeof(buffer), "[%d] %s", version_get_target(ver), version_get_gitbranch(ver));
|
||||
canvas_draw_str(canvas, 0, 50 + STATUS_BAR_Y_SHIFT, buffer);
|
||||
|
||||
} else {
|
||||
Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
|
||||
DolphinStats stats = dolphin_stats(dolphin);
|
||||
furi_record_close(RECORD_DOLPHIN);
|
||||
|
||||
uint32_t current_lvl = stats.level;
|
||||
uint32_t remaining = dolphin_state_xp_to_levelup(m->icounter);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
snprintf(buffer, sizeof(buffer), "Icounter: %lu Butthurt %lu", m->icounter, m->butthurt);
|
||||
canvas_draw_str(canvas, 5, 19 + STATUS_BAR_Y_SHIFT, buffer);
|
||||
|
||||
snprintf(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"Level: %lu To level up: %lu",
|
||||
current_lvl,
|
||||
(remaining == (uint32_t)(-1) ? remaining : 0));
|
||||
canvas_draw_str(canvas, 5, 29 + STATUS_BAR_Y_SHIFT, buffer);
|
||||
|
||||
// even if timestamp is uint64_t, it's safe to cast it to uint32_t, because furi_hal_rtc_datetime_to_timestamp only returns uint32_t
|
||||
snprintf(buffer, sizeof(buffer), "%lu", (uint32_t)m->timestamp);
|
||||
|
||||
canvas_draw_str(canvas, 5, 39 + STATUS_BAR_Y_SHIFT, buffer);
|
||||
canvas_draw_str(canvas, 0, 49 + STATUS_BAR_Y_SHIFT, "[< >] icounter value [ok] save");
|
||||
if(!ver) { //-V1051
|
||||
canvas_draw_str(canvas, 0, 30 + STATUS_BAR_Y_SHIFT, "No info");
|
||||
return;
|
||||
}
|
||||
|
||||
snprintf(
|
||||
buffer, sizeof(buffer), "%s [%s]", version_get_version(ver), version_get_builddate(ver));
|
||||
canvas_draw_str(canvas, 0, 30 + STATUS_BAR_Y_SHIFT, buffer);
|
||||
|
||||
uint16_t api_major, api_minor;
|
||||
furi_hal_info_get_api_version(&api_major, &api_minor);
|
||||
snprintf(
|
||||
buffer,
|
||||
sizeof(buffer),
|
||||
"%s%s [%d.%d] %s",
|
||||
version_get_dirty_flag(ver) ? "[!] " : "",
|
||||
version_get_githash(ver),
|
||||
api_major,
|
||||
api_minor,
|
||||
c2_ver ? c2_ver->StackTypeString : "<none>");
|
||||
canvas_draw_str(canvas, 0, 40 + STATUS_BAR_Y_SHIFT, buffer);
|
||||
|
||||
snprintf(
|
||||
buffer, sizeof(buffer), "[%d] %s", version_get_target(ver), version_get_gitbranch(ver));
|
||||
canvas_draw_str(canvas, 0, 50 + STATUS_BAR_Y_SHIFT, buffer);
|
||||
}
|
||||
|
||||
View* desktop_debug_get_view(DesktopDebugView* debug_view) {
|
||||
@@ -114,61 +89,43 @@ View* desktop_debug_get_view(DesktopDebugView* debug_view) {
|
||||
return debug_view->view;
|
||||
}
|
||||
|
||||
bool desktop_debug_input(InputEvent* event, void* context) {
|
||||
static bool desktop_debug_input(InputEvent* event, void* context) {
|
||||
furi_assert(event);
|
||||
furi_assert(context);
|
||||
|
||||
DesktopDebugView* debug_view = context;
|
||||
|
||||
if(event->type != InputTypeShort && event->type != InputTypeRepeat) {
|
||||
return false;
|
||||
}
|
||||
|
||||
DesktopViewStatsScreens current = 0;
|
||||
with_view_model(
|
||||
debug_view->view,
|
||||
DesktopDebugViewModel * model,
|
||||
{
|
||||
#ifdef SRV_DOLPHIN_STATE_DEBUG
|
||||
if((event->key == InputKeyDown) || (event->key == InputKeyUp)) {
|
||||
model->screen = !model->screen;
|
||||
}
|
||||
#endif
|
||||
current = model->screen;
|
||||
},
|
||||
true);
|
||||
|
||||
size_t count = (event->type == InputTypeRepeat) ? 10 : 1;
|
||||
if(current == DesktopViewStatsMeta) {
|
||||
if(event->key == InputKeyLeft) {
|
||||
while(count-- > 0) {
|
||||
debug_view->callback(DesktopDebugEventWrongDeed, debug_view->context);
|
||||
}
|
||||
} else if(event->key == InputKeyRight) {
|
||||
while(count-- > 0) {
|
||||
debug_view->callback(DesktopDebugEventDeed, debug_view->context);
|
||||
}
|
||||
} else if(event->key == InputKeyOk) {
|
||||
debug_view->callback(DesktopDebugEventSaveState, debug_view->context);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(event->key == InputKeyBack) {
|
||||
if(event->key == InputKeyBack && event->type == InputTypeShort) {
|
||||
debug_view->callback(DesktopDebugEventExit, debug_view->context);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void desktop_debug_enter(void* context) {
|
||||
DesktopDebugView* debug_view = context;
|
||||
furi_timer_start(debug_view->timer, furi_ms_to_ticks(1000));
|
||||
}
|
||||
|
||||
static void desktop_debug_exit(void* context) {
|
||||
DesktopDebugView* debug_view = context;
|
||||
furi_timer_stop(debug_view->timer);
|
||||
}
|
||||
void desktop_debug_timer(void* context) {
|
||||
DesktopDebugView* debug_view = context;
|
||||
view_get_model(debug_view->view);
|
||||
view_commit_model(debug_view->view, true);
|
||||
}
|
||||
|
||||
DesktopDebugView* desktop_debug_alloc() {
|
||||
DesktopDebugView* debug_view = malloc(sizeof(DesktopDebugView));
|
||||
debug_view->view = view_alloc();
|
||||
view_allocate_model(debug_view->view, ViewModelTypeLocking, sizeof(DesktopDebugViewModel));
|
||||
debug_view->timer = furi_timer_alloc(desktop_debug_timer, FuriTimerTypePeriodic, debug_view);
|
||||
view_set_context(debug_view->view, debug_view);
|
||||
view_set_draw_callback(debug_view->view, (ViewDrawCallback)desktop_debug_render);
|
||||
view_set_input_callback(debug_view->view, desktop_debug_input);
|
||||
view_set_enter_callback(debug_view->view, desktop_debug_enter);
|
||||
view_set_exit_callback(debug_view->view, desktop_debug_exit);
|
||||
|
||||
return debug_view;
|
||||
}
|
||||
@@ -176,27 +133,7 @@ DesktopDebugView* desktop_debug_alloc() {
|
||||
void desktop_debug_free(DesktopDebugView* debug_view) {
|
||||
furi_assert(debug_view);
|
||||
|
||||
furi_timer_free(debug_view->timer);
|
||||
view_free(debug_view->view);
|
||||
free(debug_view);
|
||||
}
|
||||
|
||||
void desktop_debug_get_dolphin_data(DesktopDebugView* debug_view) {
|
||||
Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
|
||||
DolphinStats stats = dolphin_stats(dolphin);
|
||||
with_view_model(
|
||||
debug_view->view,
|
||||
DesktopDebugViewModel * model,
|
||||
{
|
||||
model->icounter = stats.icounter;
|
||||
model->butthurt = stats.butthurt;
|
||||
model->timestamp = stats.timestamp;
|
||||
},
|
||||
true);
|
||||
|
||||
furi_record_close(RECORD_DOLPHIN);
|
||||
}
|
||||
|
||||
void desktop_debug_reset_screen_idx(DesktopDebugView* debug_view) {
|
||||
with_view_model(
|
||||
debug_view->view, DesktopDebugViewModel * model, { model->screen = 0; }, true);
|
||||
}
|
||||
|
||||
@@ -8,26 +8,13 @@ typedef struct DesktopDebugView DesktopDebugView;
|
||||
|
||||
typedef void (*DesktopDebugViewCallback)(DesktopEvent event, void* context);
|
||||
|
||||
// Debug info
|
||||
typedef enum {
|
||||
DesktopViewStatsFw,
|
||||
DesktopViewStatsMeta,
|
||||
DesktopViewStatsTotalCount,
|
||||
} DesktopViewStatsScreens;
|
||||
|
||||
struct DesktopDebugView {
|
||||
View* view;
|
||||
FuriTimer* timer;
|
||||
DesktopDebugViewCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
uint32_t icounter;
|
||||
uint32_t butthurt;
|
||||
uint64_t timestamp;
|
||||
DesktopViewStatsScreens screen;
|
||||
} DesktopDebugViewModel;
|
||||
|
||||
void desktop_debug_set_callback(
|
||||
DesktopDebugView* debug_view,
|
||||
DesktopDebugViewCallback callback,
|
||||
@@ -36,7 +23,5 @@ void desktop_debug_set_callback(
|
||||
View* desktop_debug_get_view(DesktopDebugView* debug_view);
|
||||
|
||||
DesktopDebugView* desktop_debug_alloc();
|
||||
void desktop_debug_free(DesktopDebugView* debug_view);
|
||||
|
||||
void desktop_debug_get_dolphin_data(DesktopDebugView* debug_view);
|
||||
void desktop_debug_reset_screen_idx(DesktopDebugView* debug_view);
|
||||
void desktop_debug_free(DesktopDebugView* debug_view);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <applications.h>
|
||||
#include <storage/storage.h>
|
||||
#include <furi_hal.h>
|
||||
#include <assets_icons.h>
|
||||
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <toolbox/path.h>
|
||||
@@ -11,7 +12,20 @@
|
||||
|
||||
#define TAG "Loader"
|
||||
#define LOADER_MAGIC_THREAD_VALUE 0xDEADBEEF
|
||||
// api
|
||||
|
||||
// helpers
|
||||
|
||||
static const char* loader_find_external_application_by_name(const char* app_name) {
|
||||
for(size_t i = 0; i < FLIPPER_EXTERNAL_APPS_COUNT; i++) {
|
||||
if(strcmp(FLIPPER_EXTERNAL_APPS[i].name, app_name) == 0) {
|
||||
return FLIPPER_EXTERNAL_APPS[i].path;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// API
|
||||
|
||||
LoaderStatus
|
||||
loader_start(Loader* loader, const char* name, const char* args, FuriString* error_message) {
|
||||
@@ -33,17 +47,33 @@ LoaderStatus loader_start_with_gui_error(Loader* loader, const char* name, const
|
||||
FuriString* error_message = furi_string_alloc();
|
||||
LoaderStatus status = loader_start(loader, name, args, error_message);
|
||||
|
||||
// TODO: we have many places where we can emit a double start, ex: desktop, menu
|
||||
// so i prefer to not show LoaderStatusErrorAppStarted error message for now
|
||||
if(status == LoaderStatusErrorUnknownApp || status == LoaderStatusErrorInternal) {
|
||||
if(status == LoaderStatusErrorUnknownApp &&
|
||||
loader_find_external_application_by_name(name) != NULL) {
|
||||
// Special case for external apps
|
||||
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
DialogMessage* message = dialog_message_alloc();
|
||||
dialog_message_set_header(message, "Update needed", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_message_set_buttons(message, NULL, NULL, NULL);
|
||||
dialog_message_set_icon(message, &I_DolphinCommon_56x48, 72, 17);
|
||||
dialog_message_set_text(
|
||||
message, "Update firmware\nto run this app", 3, 26, AlignLeft, AlignTop);
|
||||
dialog_message_show(dialogs, message);
|
||||
dialog_message_free(message);
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
} else if(status == LoaderStatusErrorUnknownApp || status == LoaderStatusErrorInternal) {
|
||||
// TODO: we have many places where we can emit a double start, ex: desktop, menu
|
||||
// so i prefer to not show LoaderStatusErrorAppStarted error message for now
|
||||
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
DialogMessage* message = dialog_message_alloc();
|
||||
dialog_message_set_header(message, "Error", 64, 0, AlignCenter, AlignTop);
|
||||
dialog_message_set_buttons(message, NULL, NULL, NULL);
|
||||
|
||||
furi_string_replace(error_message, ":", "\n");
|
||||
furi_string_replace(error_message, "/ext/apps/", "");
|
||||
furi_string_replace(error_message, ", ", "\n");
|
||||
furi_string_replace(error_message, ": ", "\n");
|
||||
|
||||
dialog_message_set_text(
|
||||
message, furi_string_get_cstr(error_message), 64, 32, AlignCenter, AlignCenter);
|
||||
message, furi_string_get_cstr(error_message), 64, 35, AlignCenter, AlignCenter);
|
||||
|
||||
dialog_message_show(dialogs, message);
|
||||
dialog_message_free(message);
|
||||
@@ -170,16 +200,6 @@ static const FlipperInternalApplication* loader_find_application_by_name(const c
|
||||
return application;
|
||||
}
|
||||
|
||||
static const char* loader_find_external_application_by_name(const char* app_name) {
|
||||
for(size_t i = 0; i < FLIPPER_EXTERNAL_APPS_COUNT; i++) {
|
||||
if(strcmp(FLIPPER_EXTERNAL_APPS[i].name, app_name) == 0) {
|
||||
return FLIPPER_EXTERNAL_APPS[i].path;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void loader_start_app_thread(Loader* loader, FlipperInternalApplicationFlag flags) {
|
||||
// setup heap trace
|
||||
FuriHalRtcHeapTrackMode mode = furi_hal_rtc_get_heap_track_mode();
|
||||
@@ -314,18 +334,16 @@ static LoaderStatus loader_start_external_app(
|
||||
}
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Mapping");
|
||||
FlipperApplicationLoadStatus load_status =
|
||||
flipper_application_map_to_memory(loader->app.fap);
|
||||
if(load_status != FlipperApplicationLoadStatusSuccess) {
|
||||
const char* err_msg = flipper_application_load_status_to_string(load_status);
|
||||
status = loader_make_status_error(
|
||||
LoaderStatusErrorInternal, error_message, "Load failed %s: %s", path, err_msg);
|
||||
LoaderStatusErrorInternal, error_message, "Load failed, %s: %s", path, err_msg);
|
||||
break;
|
||||
}
|
||||
|
||||
FURI_LOG_I(TAG, "Loaded in %zums", (size_t)(furi_get_tick() - start));
|
||||
FURI_LOG_I(TAG, "Starting app");
|
||||
|
||||
loader->app.thread = flipper_application_alloc_thread(loader->app.fap, args);
|
||||
FuriString* app_name = furi_string_alloc();
|
||||
@@ -429,7 +447,7 @@ static LoaderStatus loader_do_start_by_name(
|
||||
}
|
||||
}
|
||||
|
||||
// check external apps
|
||||
// check Faps
|
||||
{
|
||||
Storage* storage = furi_record_open(RECORD_STORAGE);
|
||||
if(storage_file_exists(storage, name)) {
|
||||
|
||||
@@ -20,7 +20,7 @@ static int32_t loader_applications_thread(void* p);
|
||||
LoaderApplications* loader_applications_alloc(void (*closed_cb)(void*), void* context) {
|
||||
LoaderApplications* loader_applications = malloc(sizeof(LoaderApplications));
|
||||
loader_applications->thread =
|
||||
furi_thread_alloc_ex(TAG, 512, loader_applications_thread, (void*)loader_applications);
|
||||
furi_thread_alloc_ex(TAG, 768, loader_applications_thread, (void*)loader_applications);
|
||||
loader_applications->closed_cb = closed_cb;
|
||||
loader_applications->context = context;
|
||||
furi_thread_start(loader_applications->thread);
|
||||
|
||||
@@ -60,7 +60,7 @@ static void loader_menu_apps_callback(void* context, uint32_t index) {
|
||||
|
||||
static void loader_menu_external_apps_callback(void* context, uint32_t index) {
|
||||
UNUSED(context);
|
||||
const char* path = FLIPPER_EXTERNAL_APPS[index].path;
|
||||
const char* path = FLIPPER_EXTERNAL_APPS[index].name;
|
||||
loader_menu_start(path);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,14 +5,29 @@
|
||||
#include <storage/storage.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
|
||||
#define APPS_COUNT (FLIPPER_APPS_COUNT + FLIPPER_EXTERNAL_APPS_COUNT)
|
||||
|
||||
#define EXTERNAL_BROWSER_NAME ("Applications")
|
||||
#define EXTERNAL_BROWSER_INDEX (FLIPPER_APPS_COUNT + 1)
|
||||
#define EXTERNAL_BROWSER_INDEX (APPS_COUNT + 1)
|
||||
|
||||
#define EXTERNAL_APPLICATION_NAME ("[External Application]")
|
||||
#define EXTERNAL_APPLICATION_INDEX (FLIPPER_APPS_COUNT + 2)
|
||||
#define EXTERNAL_APPLICATION_INDEX (APPS_COUNT + 2)
|
||||
|
||||
#define NONE_APPLICATION_INDEX (FLIPPER_APPS_COUNT + 3)
|
||||
|
||||
#define PRESELECTED_SPECIAL 0xffffffff
|
||||
|
||||
static const char* favorite_fap_get_app_name(size_t i) {
|
||||
const char* name;
|
||||
if(i < FLIPPER_APPS_COUNT) {
|
||||
name = FLIPPER_APPS[i].name;
|
||||
} else {
|
||||
name = FLIPPER_EXTERNAL_APPS[i - FLIPPER_APPS_COUNT].name;
|
||||
}
|
||||
|
||||
return name;
|
||||
}
|
||||
|
||||
static bool favorite_fap_selector_item_callback(
|
||||
FuriString* file_path,
|
||||
void* context,
|
||||
@@ -44,7 +59,7 @@ void desktop_settings_scene_favorite_on_enter(void* context) {
|
||||
|
||||
uint32_t primary_favorite =
|
||||
scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite);
|
||||
uint32_t pre_select_item = 0;
|
||||
uint32_t pre_select_item = PRESELECTED_SPECIAL;
|
||||
FavoriteApp* curr_favorite_app = NULL;
|
||||
if(primary_favorite == 0) {
|
||||
curr_favorite_app = &app->settings.favorite_primary;
|
||||
@@ -60,17 +75,13 @@ void desktop_settings_scene_favorite_on_enter(void* context) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(size_t i = 0; i < FLIPPER_APPS_COUNT; i++) {
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
FLIPPER_APPS[i].name,
|
||||
i,
|
||||
desktop_settings_scene_favorite_submenu_callback,
|
||||
app);
|
||||
for(size_t i = 0; i < APPS_COUNT; i++) {
|
||||
const char* name = favorite_fap_get_app_name(i);
|
||||
|
||||
submenu_add_item(submenu, name, i, desktop_settings_scene_favorite_submenu_callback, app);
|
||||
|
||||
// Select favorite item in submenu
|
||||
if(!curr_favorite_app->is_external &&
|
||||
!strcmp(FLIPPER_APPS[i].name, curr_favorite_app->name_or_path)) {
|
||||
if(!strcmp(name, curr_favorite_app->name_or_path)) {
|
||||
pre_select_item = i;
|
||||
}
|
||||
}
|
||||
@@ -91,7 +102,7 @@ void desktop_settings_scene_favorite_on_enter(void* context) {
|
||||
desktop_settings_scene_favorite_submenu_callback,
|
||||
app);
|
||||
|
||||
if(curr_favorite_app->is_external) {
|
||||
if(pre_select_item == PRESELECTED_SPECIAL) {
|
||||
if(curr_favorite_app->name_or_path[0] == '\0') {
|
||||
pre_select_item = EXTERNAL_BROWSER_INDEX;
|
||||
} else {
|
||||
@@ -143,7 +154,6 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == EXTERNAL_BROWSER_INDEX) {
|
||||
curr_favorite_app->is_external = true;
|
||||
curr_favorite_app->name_or_path[0] = '\0';
|
||||
consumed = true;
|
||||
} else if(event.event == EXTERNAL_APPLICATION_INDEX) {
|
||||
@@ -164,7 +174,6 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e
|
||||
|
||||
if(dialog_file_browser_show(app->dialogs, temp_path, temp_path, &browser_options)) {
|
||||
submenu_reset(app->submenu); // Prevent menu from being shown when we exiting scene
|
||||
curr_favorite_app->is_external = true;
|
||||
strncpy(
|
||||
curr_favorite_app->name_or_path,
|
||||
furi_string_get_cstr(temp_path),
|
||||
@@ -172,13 +181,11 @@ bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent e
|
||||
consumed = true;
|
||||
}
|
||||
} else if(event.event == NONE_APPLICATION_INDEX) {
|
||||
curr_favorite_app->is_external = false;
|
||||
strncpy(curr_favorite_app->name_or_path, "n", MAX_APP_LENGTH);
|
||||
consumed = true;
|
||||
} else {
|
||||
curr_favorite_app->is_external = false;
|
||||
strncpy(
|
||||
curr_favorite_app->name_or_path, FLIPPER_APPS[event.event].name, MAX_APP_LENGTH);
|
||||
const char* name = favorite_fap_get_app_name(event.event);
|
||||
if(name) strncpy(curr_favorite_app->name_or_path, name, MAX_APP_LENGTH);
|
||||
consumed = true;
|
||||
}
|
||||
if(consumed) {
|
||||
|
||||
Reference in New Issue
Block a user