mirror of
https://github.com/Next-Flip/Momentum-Firmware.git
synced 2026-05-13 15:58:36 -07:00
New 'Compact' menu style (#388)
This commit is contained in:
@@ -40,11 +40,13 @@ static void ibutton_make_app_folder(iButton* ibutton) {
|
|||||||
furi_record_close(RECORD_STORAGE);
|
furi_record_close(RECORD_STORAGE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Callback function for handling RPC commands
|
||||||
static void ibutton_rpc_command_callback(RpcAppSystemEvent event, void* context) {
|
static void ibutton_rpc_command_callback(RpcAppSystemEvent event, void* context) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
iButton* ibutton = context;
|
iButton* ibutton = context;
|
||||||
|
|
||||||
if(event == RpcAppEventSessionClose) {
|
if(event == RpcAppEventSessionClose) {
|
||||||
|
// Send a custom event and detach from RPC on session close, load, and exit
|
||||||
view_dispatcher_send_custom_event(
|
view_dispatcher_send_custom_event(
|
||||||
ibutton->view_dispatcher, iButtonCustomEventRpcSessionClose);
|
ibutton->view_dispatcher, iButtonCustomEventRpcSessionClose);
|
||||||
rpc_system_app_set_callback(ibutton->rpc, NULL, NULL);
|
rpc_system_app_set_callback(ibutton->rpc, NULL, NULL);
|
||||||
@@ -61,6 +63,7 @@ static void ibutton_rpc_command_callback(RpcAppSystemEvent event, void* context)
|
|||||||
bool ibutton_custom_event_callback(void* context, uint32_t event) {
|
bool ibutton_custom_event_callback(void* context, uint32_t event) {
|
||||||
furi_assert(context);
|
furi_assert(context);
|
||||||
iButton* ibutton = context;
|
iButton* ibutton = context;
|
||||||
|
|
||||||
return scene_manager_handle_custom_event(ibutton->scene_manager, event);
|
return scene_manager_handle_custom_event(ibutton->scene_manager, event);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,6 +79,7 @@ void ibutton_tick_event_callback(void* context) {
|
|||||||
scene_manager_handle_tick_event(ibutton->scene_manager);
|
scene_manager_handle_tick_event(ibutton->scene_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Allocate memory and initialize the iButton structure
|
||||||
iButton* ibutton_alloc() {
|
iButton* ibutton_alloc() {
|
||||||
iButton* ibutton = malloc(sizeof(iButton));
|
iButton* ibutton = malloc(sizeof(iButton));
|
||||||
|
|
||||||
@@ -133,6 +137,7 @@ iButton* ibutton_alloc() {
|
|||||||
void ibutton_free(iButton* ibutton) {
|
void ibutton_free(iButton* ibutton) {
|
||||||
furi_assert(ibutton);
|
furi_assert(ibutton);
|
||||||
|
|
||||||
|
// Remove and free views, then free the view dispatcher and scene manager
|
||||||
view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewLoading);
|
view_dispatcher_remove_view(ibutton->view_dispatcher, iButtonViewLoading);
|
||||||
loading_free(ibutton->loading);
|
loading_free(ibutton->loading);
|
||||||
|
|
||||||
@@ -154,6 +159,7 @@ void ibutton_free(iButton* ibutton) {
|
|||||||
view_dispatcher_free(ibutton->view_dispatcher);
|
view_dispatcher_free(ibutton->view_dispatcher);
|
||||||
scene_manager_free(ibutton->scene_manager);
|
scene_manager_free(ibutton->scene_manager);
|
||||||
|
|
||||||
|
// Close records and free worker and key
|
||||||
furi_record_close(RECORD_NOTIFICATION);
|
furi_record_close(RECORD_NOTIFICATION);
|
||||||
ibutton->notifications = NULL;
|
ibutton->notifications = NULL;
|
||||||
|
|
||||||
@@ -176,6 +182,7 @@ void ibutton_free(iButton* ibutton) {
|
|||||||
bool ibutton_load_key(iButton* ibutton) {
|
bool ibutton_load_key(iButton* ibutton) {
|
||||||
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewLoading);
|
view_dispatcher_switch_to_view(ibutton->view_dispatcher, iButtonViewLoading);
|
||||||
|
|
||||||
|
// Attempt to load the key using protocols
|
||||||
const bool success = ibutton_protocols_load(
|
const bool success = ibutton_protocols_load(
|
||||||
ibutton->protocols, ibutton->key, furi_string_get_cstr(ibutton->file_path));
|
ibutton->protocols, ibutton->key, furi_string_get_cstr(ibutton->file_path));
|
||||||
|
|
||||||
@@ -183,6 +190,7 @@ bool ibutton_load_key(iButton* ibutton) {
|
|||||||
dialog_message_show_storage_error(ibutton->dialogs, "Cannot load\nkey file");
|
dialog_message_show_storage_error(ibutton->dialogs, "Cannot load\nkey file");
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
// Extract and store the key name
|
||||||
FuriString* tmp = furi_string_alloc();
|
FuriString* tmp = furi_string_alloc();
|
||||||
|
|
||||||
path_extract_filename(ibutton->file_path, tmp, true);
|
path_extract_filename(ibutton->file_path, tmp, true);
|
||||||
@@ -194,6 +202,7 @@ bool ibutton_load_key(iButton* ibutton) {
|
|||||||
return success;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Select and load a key for iButton using the file browser
|
||||||
bool ibutton_select_and_load_key(iButton* ibutton) {
|
bool ibutton_select_and_load_key(iButton* ibutton) {
|
||||||
DialogsFileBrowserOptions browser_options;
|
DialogsFileBrowserOptions browser_options;
|
||||||
bool success = false;
|
bool success = false;
|
||||||
@@ -254,6 +263,7 @@ void ibutton_notification_message(iButton* ibutton, uint32_t message) {
|
|||||||
notification_message(ibutton->notifications, ibutton_notification_sequences[message]);
|
notification_message(ibutton->notifications, ibutton_notification_sequences[message]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Callback functions for submenu and widget actions
|
||||||
void ibutton_submenu_callback(void* context, uint32_t index) {
|
void ibutton_submenu_callback(void* context, uint32_t index) {
|
||||||
iButton* ibutton = context;
|
iButton* ibutton = context;
|
||||||
view_dispatcher_send_custom_event(ibutton->view_dispatcher, index);
|
view_dispatcher_send_custom_event(ibutton->view_dispatcher, index);
|
||||||
@@ -278,10 +288,12 @@ int32_t ibutton_app(char* arg) {
|
|||||||
if(sscanf(arg, "RPC %lX", (uint32_t*)&ibutton->rpc) == 1) {
|
if(sscanf(arg, "RPC %lX", (uint32_t*)&ibutton->rpc) == 1) {
|
||||||
FURI_LOG_D(TAG, "Running in RPC mode");
|
FURI_LOG_D(TAG, "Running in RPC mode");
|
||||||
|
|
||||||
|
// Attach to RPC and handle RPC events
|
||||||
rpc_system_app_set_callback(ibutton->rpc, ibutton_rpc_command_callback, ibutton);
|
rpc_system_app_set_callback(ibutton->rpc, ibutton_rpc_command_callback, ibutton);
|
||||||
rpc_system_app_send_started(ibutton->rpc);
|
rpc_system_app_send_started(ibutton->rpc);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
// Set the file_path and attempt to load the key
|
||||||
furi_string_set(ibutton->file_path, (const char*)arg);
|
furi_string_set(ibutton->file_path, (const char*)arg);
|
||||||
key_loaded = ibutton_load_key(ibutton);
|
key_loaded = ibutton_load_key(ibutton);
|
||||||
}
|
}
|
||||||
@@ -294,6 +306,7 @@ int32_t ibutton_app(char* arg) {
|
|||||||
dolphin_deed(DolphinDeedIbuttonEmulate);
|
dolphin_deed(DolphinDeedIbuttonEmulate);
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
// Attach to GUI (fullscreen) and set the initial scene based on key loading
|
||||||
view_dispatcher_attach_to_gui(
|
view_dispatcher_attach_to_gui(
|
||||||
ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen);
|
ibutton->view_dispatcher, ibutton->gui, ViewDispatcherTypeFullscreen);
|
||||||
if(key_loaded) { //-V547
|
if(key_loaded) { //-V547
|
||||||
@@ -311,6 +324,7 @@ int32_t ibutton_app(char* arg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if(ibutton->rpc) {
|
if(ibutton->rpc) {
|
||||||
|
// Detach from RPC and handle RPC exit
|
||||||
rpc_system_app_set_callback(ibutton->rpc, NULL, NULL);
|
rpc_system_app_set_callback(ibutton->rpc, NULL, NULL);
|
||||||
rpc_system_app_send_exited(ibutton->rpc);
|
rpc_system_app_send_exited(ibutton->rpc);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ const char* const menu_style_names[MenuStyleCount] = {
|
|||||||
"Vertical",
|
"Vertical",
|
||||||
"C64",
|
"C64",
|
||||||
"Eurocorp",
|
"Eurocorp",
|
||||||
|
"Compact",
|
||||||
};
|
};
|
||||||
static void xtreme_app_scene_interface_mainmenu_menu_style_changed(VariableItem* item) {
|
static void xtreme_app_scene_interface_mainmenu_menu_style_changed(VariableItem* item) {
|
||||||
XtremeApp* app = variable_item_get_context(item);
|
XtremeApp* app = variable_item_get_context(item);
|
||||||
|
|||||||
@@ -362,6 +362,48 @@ static void menu_draw_callback(Canvas* canvas, void* _model) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case MenuStyleCompact: {
|
||||||
|
FuriString* memstr = furi_string_alloc();
|
||||||
|
|
||||||
|
size_t index;
|
||||||
|
size_t y_off, x_off;
|
||||||
|
|
||||||
|
canvas_set_font(canvas, FontKeyboard);
|
||||||
|
|
||||||
|
for(size_t i = 0; i < 2; i++) {
|
||||||
|
for(size_t j = 0; j < 7; j++) {
|
||||||
|
index = i * 7 + j + (position - (position % 14));
|
||||||
|
if(index >= items_count) continue;
|
||||||
|
y_off = (9 * j) - 4;
|
||||||
|
x_off = 64 * i;
|
||||||
|
bool selected = index == position;
|
||||||
|
size_t scroll_counter = menu_scroll_counter(model, selected);
|
||||||
|
if(selected) {
|
||||||
|
canvas_draw_box(canvas, x_off, y_off + 4, 64, 9);
|
||||||
|
canvas_set_color(canvas, ColorWhite);
|
||||||
|
}
|
||||||
|
item = MenuItemArray_get(model->items, index);
|
||||||
|
menu_short_name(item, name);
|
||||||
|
|
||||||
|
FuriString* item_str = furi_string_alloc();
|
||||||
|
|
||||||
|
furi_string_printf(item_str, "%s", furi_string_get_cstr(name));
|
||||||
|
|
||||||
|
elements_scrollable_text_line(
|
||||||
|
canvas, x_off + 2, y_off + 12, 64, item_str, scroll_counter, false);
|
||||||
|
|
||||||
|
furi_string_free(item_str);
|
||||||
|
|
||||||
|
if(selected) {
|
||||||
|
canvas_set_color(canvas, ColorBlack);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
furi_string_free(memstr);
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -612,6 +654,13 @@ static void menu_process_up(Menu* menu) {
|
|||||||
position = count - 1;
|
position = count - 1;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case MenuStyleCompact:
|
||||||
|
if(position > 0) {
|
||||||
|
position--;
|
||||||
|
} else {
|
||||||
|
position = count - 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -660,6 +709,13 @@ static void menu_process_down(Menu* menu) {
|
|||||||
position = 0;
|
position = 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case MenuStyleCompact:
|
||||||
|
if(position < count - 1) {
|
||||||
|
position++;
|
||||||
|
} else {
|
||||||
|
position = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -712,6 +768,14 @@ static void menu_process_left(Menu* menu) {
|
|||||||
} else if((position % 10) >= 5) {
|
} else if((position % 10) >= 5) {
|
||||||
position = position - 5;
|
position = position - 5;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case MenuStyleCompact:
|
||||||
|
if((position % 16) < 8) {
|
||||||
|
position = position + 7;
|
||||||
|
} else if((position % 16) >= 8) {
|
||||||
|
position = position - 7;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -769,6 +833,14 @@ static void menu_process_right(Menu* menu) {
|
|||||||
} else if((position % 10) >= 5 && position < count) {
|
} else if((position % 10) >= 5 && position < count) {
|
||||||
position = position - 5;
|
position = position - 5;
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
case MenuStyleCompact:
|
||||||
|
if(position >= (count - count) && (position % 16) < 8) {
|
||||||
|
position = position + 7;
|
||||||
|
} else if((position % 16) >= 8 && position < count) {
|
||||||
|
position = position - 7;
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -793,4 +865,4 @@ static void menu_process_ok(Menu* menu) {
|
|||||||
if(item && item->callback) {
|
if(item && item->callback) {
|
||||||
item->callback(item->callback_context, item->index);
|
item->callback(item->callback_context, item->index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -33,6 +33,7 @@ typedef enum {
|
|||||||
MenuStyleVertical,
|
MenuStyleVertical,
|
||||||
MenuStyleC64,
|
MenuStyleC64,
|
||||||
MenuStyleEurocorp,
|
MenuStyleEurocorp,
|
||||||
|
MenuStyleCompact,
|
||||||
MenuStyleCount,
|
MenuStyleCount,
|
||||||
} MenuStyle;
|
} MenuStyle;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user