mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-12 19:38:36 -07:00
Merge branch 'dev' of https://github.com/DarkFlippers/unleashed-firmware into xfw-dev
This commit is contained in:
@@ -51,6 +51,12 @@ extern const size_t FLIPPER_ON_SYSTEM_START_COUNT;
|
||||
extern const FlipperInternalApplication FLIPPER_SYSTEM_APPS[];
|
||||
extern const size_t FLIPPER_SYSTEM_APPS_COUNT;
|
||||
|
||||
/* Debug apps
|
||||
* Can only be spawned by loader by name
|
||||
*/
|
||||
extern const FlipperInternalApplication FLIPPER_DEBUG_APPS[];
|
||||
extern const size_t FLIPPER_DEBUG_APPS_COUNT;
|
||||
|
||||
extern const FlipperInternalApplication FLIPPER_ARCHIVE;
|
||||
|
||||
/* Settings list
|
||||
|
||||
@@ -96,7 +96,7 @@ static void desktop_clock_draw_callback(Canvas* canvas, void* context) {
|
||||
char buffer[20];
|
||||
snprintf(buffer, sizeof(buffer), "%02u:%02u", hour, desktop->time_minute);
|
||||
|
||||
// ToDo: never do that, may cause visual glitches
|
||||
// TODO FL-3515: never do that, may cause visual glitches
|
||||
view_port_set_width(
|
||||
desktop->clock_viewport,
|
||||
canvas_string_width(canvas, buffer) - 1 + (desktop->time_minute % 10 == 1));
|
||||
@@ -365,12 +365,7 @@ Desktop* desktop_alloc() {
|
||||
}
|
||||
gui_add_view_port(desktop->gui, desktop->stealth_mode_icon_viewport, GuiLayerStatusBarLeft);
|
||||
|
||||
// Special case: autostart application is already running
|
||||
desktop->loader = furi_record_open(RECORD_LOADER);
|
||||
if(loader_is_locked(desktop->loader) &&
|
||||
animation_manager_is_animation_loaded(desktop->animation_manager)) {
|
||||
animation_manager_unload_and_stall_animation(desktop->animation_manager);
|
||||
}
|
||||
|
||||
desktop->notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
desktop->app_start_stop_subscription = furi_pubsub_subscribe(
|
||||
@@ -510,6 +505,12 @@ int32_t desktop_srv(void* p) {
|
||||
scene_manager_next_scene(desktop->scene_manager, DesktopSceneFault);
|
||||
}
|
||||
|
||||
// Special case: autostart application is already running
|
||||
if(loader_is_locked(desktop->loader) &&
|
||||
animation_manager_is_animation_loaded(desktop->animation_manager)) {
|
||||
animation_manager_unload_and_stall_animation(desktop->animation_manager);
|
||||
}
|
||||
|
||||
view_dispatcher_run(desktop->view_dispatcher);
|
||||
|
||||
furi_crash("That was unexpected");
|
||||
|
||||
@@ -93,6 +93,10 @@ bool desktop_scene_locked_on_event(void* context, SceneManagerEvent event) {
|
||||
desktop_unlock(desktop);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopLockedEventCoversClosed:
|
||||
notification_message(desktop->notification, &sequence_display_backlight_off);
|
||||
consumed = true;
|
||||
break;
|
||||
case DesktopLockedEventUpdate:
|
||||
if(desktop_view_locked_is_locked_hint_visible(desktop->locked_view)) {
|
||||
notification_message(
|
||||
|
||||
@@ -13,6 +13,7 @@ typedef enum {
|
||||
DesktopLockedEventUnlocked,
|
||||
DesktopLockedEventUpdate,
|
||||
DesktopLockedEventShowPinInput,
|
||||
DesktopLockedEventCoversClosed,
|
||||
|
||||
DesktopPinInputEventResetWrongPinLabel,
|
||||
DesktopPinInputEventUnlocked,
|
||||
|
||||
@@ -165,6 +165,7 @@ void desktop_view_locked_update(DesktopViewLocked* locked_view) {
|
||||
|
||||
if(view_state == DesktopViewLockedStateCoverClosing &&
|
||||
!desktop_view_locked_cover_move(model, true)) {
|
||||
locked_view->callback(DesktopLockedEventCoversClosed, locked_view->context);
|
||||
model->view_state = DesktopViewLockedStateLocked;
|
||||
} else if(
|
||||
view_state == DesktopViewLockedStateCoverOpening &&
|
||||
|
||||
@@ -259,11 +259,11 @@ static size_t
|
||||
}
|
||||
|
||||
if(len_px > px_left) {
|
||||
uint8_t excess_symbols_approximately =
|
||||
roundf((float)(len_px - px_left) / ((float)len_px / (float)text_size));
|
||||
size_t excess_symbols_approximately =
|
||||
ceilf((float)(len_px - px_left) / ((float)len_px / (float)text_size));
|
||||
// reduce to 5 to be sure dash fit, and next line will be at least 5 symbols long
|
||||
if(excess_symbols_approximately > 0) {
|
||||
excess_symbols_approximately = MAX(excess_symbols_approximately, 5);
|
||||
excess_symbols_approximately = MAX(excess_symbols_approximately, 5u);
|
||||
result = text_size - excess_symbols_approximately - 1;
|
||||
} else {
|
||||
result = text_size;
|
||||
|
||||
@@ -29,6 +29,9 @@ typedef struct {
|
||||
const Icon* name_selected;
|
||||
} IconElement;
|
||||
|
||||
LIST_DEF(IconList, IconElement, M_POD_OPLIST)
|
||||
#define M_OPL_IconList_t() LIST_OPLIST(IconList)
|
||||
|
||||
typedef struct ButtonItem {
|
||||
uint32_t index;
|
||||
ButtonItemCallback callback;
|
||||
@@ -47,6 +50,7 @@ struct ButtonPanel {
|
||||
|
||||
typedef struct {
|
||||
ButtonMatrix_t button_matrix;
|
||||
IconList_t icons;
|
||||
LabelList_t labels;
|
||||
uint16_t reserve_x;
|
||||
uint16_t reserve_y;
|
||||
@@ -114,7 +118,6 @@ void button_panel_reserve(ButtonPanel* button_panel, size_t reserve_x, size_t re
|
||||
ButtonArray_t* array = ButtonMatrix_get(model->button_matrix, i);
|
||||
ButtonArray_init(*array);
|
||||
ButtonArray_reserve(*array, reserve_x);
|
||||
// TODO: do we need to clear allocated memory of ptr-s to ButtonItem ??
|
||||
}
|
||||
LabelList_init(model->labels);
|
||||
},
|
||||
@@ -158,6 +161,7 @@ void button_panel_reset(ButtonPanel* button_panel) {
|
||||
model->selected_item_x = 0;
|
||||
model->selected_item_y = 0;
|
||||
LabelList_reset(model->labels);
|
||||
IconList_reset(model->icons);
|
||||
ButtonMatrix_reset(model->button_matrix);
|
||||
},
|
||||
true);
|
||||
@@ -220,9 +224,17 @@ static void button_panel_view_draw_callback(Canvas* canvas, void* _model) {
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
|
||||
for
|
||||
M_EACH(icon, model->icons, IconList_t) {
|
||||
canvas_draw_icon(canvas, icon->x, icon->y, icon->name);
|
||||
}
|
||||
|
||||
for(size_t x = 0; x < model->reserve_x; ++x) {
|
||||
for(size_t y = 0; y < model->reserve_y; ++y) {
|
||||
ButtonItem* button_item = *button_panel_get_item(model, x, y);
|
||||
if(!button_item) {
|
||||
continue;
|
||||
}
|
||||
const Icon* icon_name = button_item->icon.name;
|
||||
if((model->selected_item_x == x) && (model->selected_item_y == y)) {
|
||||
icon_name = button_item->icon.name_selected;
|
||||
@@ -418,3 +430,24 @@ void button_panel_add_label(
|
||||
},
|
||||
true);
|
||||
}
|
||||
|
||||
// Draw an icon but don't make it a button.
|
||||
void button_panel_add_icon(
|
||||
ButtonPanel* button_panel,
|
||||
uint16_t x,
|
||||
uint16_t y,
|
||||
const Icon* icon_name) {
|
||||
furi_assert(button_panel);
|
||||
|
||||
with_view_model( //-V773
|
||||
button_panel->view,
|
||||
ButtonPanelModel * model,
|
||||
{
|
||||
IconElement* icon = IconList_push_raw(model->icons);
|
||||
icon->x = x;
|
||||
icon->y = y;
|
||||
icon->name = icon_name;
|
||||
icon->name_selected = icon_name;
|
||||
},
|
||||
true);
|
||||
}
|
||||
@@ -106,6 +106,19 @@ void button_panel_add_label(
|
||||
Font font,
|
||||
const char* label_str);
|
||||
|
||||
/** Add a non-button icon to button_panel module.
|
||||
*
|
||||
* @param button_panel ButtonPanel instance
|
||||
* @param x x-coordinate to place icon
|
||||
* @param y y-coordinate to place icon
|
||||
* @param icon_name name of the icon to draw
|
||||
*/
|
||||
void button_panel_add_icon(
|
||||
ButtonPanel* button_panel,
|
||||
uint16_t x,
|
||||
uint16_t y,
|
||||
const Icon* icon_name);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -272,7 +272,7 @@ void view_dispatcher_handle_input(ViewDispatcher* view_dispatcher, InputEvent* e
|
||||
} else if(view_dispatcher->navigation_event_callback) {
|
||||
// Dispatch navigation event
|
||||
if(!view_dispatcher->navigation_event_callback(view_dispatcher->event_context)) {
|
||||
// TODO: should we allow view_dispatcher to stop without navigation_event_callback?
|
||||
// TODO FL-3514: should we allow view_dispatcher to stop without navigation_event_callback?
|
||||
view_dispatcher_stop(view_dispatcher);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
#include "gui.h"
|
||||
#include "gui_i.h"
|
||||
|
||||
// TODO add mutex to view_port ops
|
||||
// TODO FL-3498: add mutex to view_port ops
|
||||
|
||||
_Static_assert(ViewPortOrientationMAX == 4, "Incorrect ViewPortOrientation count");
|
||||
_Static_assert(
|
||||
|
||||
@@ -10,6 +10,19 @@
|
||||
|
||||
static_assert(!has_hash_collisions(elf_api_table), "Detected API method hash collision!");
|
||||
|
||||
#ifdef APP_UNIT_TESTS
|
||||
constexpr HashtableApiInterface mock_elf_api_interface{
|
||||
{
|
||||
.api_version_major = 0,
|
||||
.api_version_minor = 0,
|
||||
.resolver_callback = &elf_resolve_from_hashtable,
|
||||
},
|
||||
.table_cbegin = nullptr,
|
||||
.table_cend = nullptr,
|
||||
};
|
||||
|
||||
const ElfApiInterface* const firmware_api_interface = &mock_elf_api_interface;
|
||||
#else
|
||||
constexpr HashtableApiInterface elf_api_interface{
|
||||
{
|
||||
.api_version_major = (elf_api_version >> 16),
|
||||
@@ -19,10 +32,10 @@ constexpr HashtableApiInterface elf_api_interface{
|
||||
.table_cbegin = elf_api_table.cbegin(),
|
||||
.table_cend = elf_api_table.cend(),
|
||||
};
|
||||
|
||||
const ElfApiInterface* const firmware_api_interface = &elf_api_interface;
|
||||
#endif
|
||||
|
||||
extern "C" void furi_hal_info_get_api_version(uint16_t* major, uint16_t* minor) {
|
||||
*major = elf_api_interface.api_version_major;
|
||||
*minor = elf_api_interface.api_version_minor;
|
||||
*major = firmware_api_interface->api_version_major;
|
||||
*minor = firmware_api_interface->api_version_minor;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "loader.h"
|
||||
#include "core/core_defines.h"
|
||||
#include "loader_i.h"
|
||||
#include <applications.h>
|
||||
#include <storage/storage.h>
|
||||
@@ -47,7 +48,7 @@ LoaderStatus
|
||||
}
|
||||
|
||||
static void loader_show_gui_error(LoaderStatus status, FuriString* error_message) {
|
||||
// TODO: we have many places where we can emit a double start, ex: desktop, menu
|
||||
// TODO FL-3522: 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) {
|
||||
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
@@ -315,18 +316,25 @@ static FlipperInternalApplication const* loader_find_application_by_name_in_list
|
||||
}
|
||||
|
||||
static const FlipperInternalApplication* loader_find_application_by_name(const char* name) {
|
||||
const FlipperInternalApplication* application = NULL;
|
||||
application = loader_find_application_by_name_in_list(name, FLIPPER_APPS, FLIPPER_APPS_COUNT);
|
||||
if(!application) {
|
||||
application = loader_find_application_by_name_in_list(
|
||||
name, FLIPPER_SETTINGS_APPS, FLIPPER_SETTINGS_APPS_COUNT);
|
||||
}
|
||||
if(!application) {
|
||||
application = loader_find_application_by_name_in_list(
|
||||
name, FLIPPER_SYSTEM_APPS, FLIPPER_SYSTEM_APPS_COUNT);
|
||||
const struct {
|
||||
const FlipperInternalApplication* list;
|
||||
const uint32_t count;
|
||||
} lists[] = {
|
||||
{FLIPPER_APPS, FLIPPER_APPS_COUNT},
|
||||
{FLIPPER_SETTINGS_APPS, FLIPPER_SETTINGS_APPS_COUNT},
|
||||
{FLIPPER_SYSTEM_APPS, FLIPPER_SYSTEM_APPS_COUNT},
|
||||
{FLIPPER_DEBUG_APPS, FLIPPER_DEBUG_APPS_COUNT},
|
||||
};
|
||||
|
||||
for(size_t i = 0; i < COUNT_OF(lists); i++) {
|
||||
const FlipperInternalApplication* application =
|
||||
loader_find_application_by_name_in_list(name, lists[i].list, lists[i].count);
|
||||
if(application) {
|
||||
return application;
|
||||
}
|
||||
}
|
||||
|
||||
return application;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void loader_start_app_thread(Loader* loader, FlipperInternalApplicationFlag flags) {
|
||||
@@ -382,9 +390,7 @@ static void loader_log_status_error(
|
||||
furi_string_vprintf(error_message, format, args);
|
||||
FURI_LOG_E(TAG, "Status [%d]: %s", status, furi_string_get_cstr(error_message));
|
||||
} else {
|
||||
FuriString* tmp = furi_string_alloc();
|
||||
FURI_LOG_E(TAG, "Status [%d]: %s", status, furi_string_get_cstr(tmp));
|
||||
furi_string_free(tmp);
|
||||
FURI_LOG_E(TAG, "Status [%d]", status);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -665,7 +671,9 @@ int32_t loader_srv(void* p) {
|
||||
FLIPPER_ON_SYSTEM_START[i]();
|
||||
}
|
||||
|
||||
if(FLIPPER_AUTORUN_APP_NAME && strlen(FLIPPER_AUTORUN_APP_NAME)) {
|
||||
if((furi_hal_rtc_get_boot_mode() == FuriHalRtcBootModeNormal) && FLIPPER_AUTORUN_APP_NAME &&
|
||||
strlen(FLIPPER_AUTORUN_APP_NAME)) {
|
||||
FURI_LOG_I(TAG, "Starting autorun app: %s", FLIPPER_AUTORUN_APP_NAME);
|
||||
loader_do_start_by_name(loader, FLIPPER_AUTORUN_APP_NAME, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ static void loader_cli_info(Loader* loader) {
|
||||
if(!loader_is_locked(loader)) {
|
||||
printf("No application is running\r\n");
|
||||
} else {
|
||||
// TODO: print application name ???
|
||||
// TODO FL-3513: print application name ???
|
||||
printf("Application is running\r\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ static void rpc_system_gui_start_virtual_display_process(const PB_Main* request,
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO: consider refactoring
|
||||
// TODO FL-3511: consider refactoring
|
||||
// Using display framebuffer size as an XBM buffer size is like comparing apples and oranges
|
||||
// Glad they both are 1024 for now
|
||||
size_t buffer_size = canvas_get_buffer_size(rpc_gui->gui->canvas);
|
||||
|
||||
@@ -430,7 +430,7 @@ static FS_Error storage_process_common_fs_info(
|
||||
}
|
||||
|
||||
/****************** Raw SD API ******************/
|
||||
// TODO think about implementing a custom storage API to split that kind of api linkage
|
||||
// TODO FL-3521: think about implementing a custom storage API to split that kind of api linkage
|
||||
#include "storages/storage_ext.h"
|
||||
|
||||
static FS_Error storage_process_sd_format(Storage* app) {
|
||||
|
||||
@@ -100,7 +100,7 @@ FS_Error sd_unmount_card(StorageData* storage) {
|
||||
storage->status = StorageStatusNotReady;
|
||||
error = FR_DISK_ERR;
|
||||
|
||||
// TODO do i need to close the files?
|
||||
// TODO FL-3522: do i need to close the files?
|
||||
f_mount(0, sd_data->path, 0);
|
||||
|
||||
return storage_ext_parse_error(error);
|
||||
|
||||
Reference in New Issue
Block a user