[FL-1824] Dolphin refactoring (#701)
* refactoring p1 * refactoring p2 * cleanups * locked screen refresh rate fix * better locked view logic * seperate dolphin service and desktop app * Desktop: Favorite app acess (Left key), Settings app * Desktop settings version, submenu header * remove unused icon anomation + naming fix Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
		
							parent
							
								
									a8981d317a
								
							
						
					
					
						commit
						1c4e6ec74d
					
				| @ -14,6 +14,7 @@ extern int32_t notification_srv(void* p); | |||||||
| extern int32_t power_observer_srv(void* p); | extern int32_t power_observer_srv(void* p); | ||||||
| extern int32_t power_srv(void* p); | extern int32_t power_srv(void* p); | ||||||
| extern int32_t storage_srv(void* p); | extern int32_t storage_srv(void* p); | ||||||
|  | extern int32_t desktop_srv(void* p); | ||||||
| 
 | 
 | ||||||
| // Apps
 | // Apps
 | ||||||
| extern int32_t accessor_app(void* p); | extern int32_t accessor_app(void* p); | ||||||
| @ -52,6 +53,7 @@ extern void power_cli_init(); | |||||||
| extern int32_t notification_settings_app(void* p); | extern int32_t notification_settings_app(void* p); | ||||||
| extern int32_t storage_settings_app(void* p); | extern int32_t storage_settings_app(void* p); | ||||||
| extern int32_t bt_settings_app(void* p); | extern int32_t bt_settings_app(void* p); | ||||||
|  | extern int32_t desktop_settings_app(void* p); | ||||||
| extern int32_t about_settings_app(void* p); | extern int32_t about_settings_app(void* p); | ||||||
| extern int32_t power_settings_app(void* p); | extern int32_t power_settings_app(void* p); | ||||||
| 
 | 
 | ||||||
| @ -73,6 +75,10 @@ const FlipperApplication FLIPPER_SERVICES[] = { | |||||||
|     {.app = dolphin_srv, .name = "Dolphin", .stack_size = 1024, .icon = NULL}, |     {.app = dolphin_srv, .name = "Dolphin", .stack_size = 1024, .icon = NULL}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef SRV_DESKTOP | ||||||
|  |     {.app = desktop_srv, .name = "Desktop", .stack_size = 1024, .icon = NULL}, | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #ifdef SRV_GUI | #ifdef SRV_GUI | ||||||
|     {.app = gui_srv, .name = "Gui", .stack_size = 8192, .icon = NULL}, |     {.app = gui_srv, .name = "Gui", .stack_size = 8192, .icon = NULL}, | ||||||
| #endif | #endif | ||||||
| @ -282,6 +288,10 @@ const FlipperApplication FLIPPER_SETTINGS_APPS[] = { | |||||||
|     {.app = power_settings_app, .name = "Power", .stack_size = 1024, .icon = NULL}, |     {.app = power_settings_app, .name = "Power", .stack_size = 1024, .icon = NULL}, | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
|  | #ifdef APP_DESKTOP | ||||||
|  |     {.app = desktop_settings_app, .name = "Desktop", .stack_size = 1024, .icon = NULL}, | ||||||
|  | #endif | ||||||
|  | 
 | ||||||
| #ifdef APP_ABOUT | #ifdef APP_ABOUT | ||||||
|     {.app = about_settings_app, .name = "About", .stack_size = 1024, .icon = NULL}, |     {.app = about_settings_app, .name = "About", .stack_size = 1024, .icon = NULL}, | ||||||
| #endif | #endif | ||||||
|  | |||||||
| @ -25,6 +25,7 @@ SRV_POWER_OBSERVER = 1 | |||||||
| SRV_STORAGE = 1 | SRV_STORAGE = 1 | ||||||
| 
 | 
 | ||||||
| # Apps
 | # Apps
 | ||||||
|  | SRV_DESKTOP = 1 | ||||||
| APP_ARCHIVE = 1 | APP_ARCHIVE = 1 | ||||||
| APP_GPIO_TEST = 1 | APP_GPIO_TEST = 1 | ||||||
| APP_IBUTTON = 1 | APP_IBUTTON = 1 | ||||||
| @ -95,6 +96,12 @@ ifeq ($(APP_UNIT_TESTS), 1) | |||||||
| CFLAGS		+= -DAPP_UNIT_TESTS | CFLAGS		+= -DAPP_UNIT_TESTS | ||||||
| endif | endif | ||||||
| 
 | 
 | ||||||
|  | SRV_DESKTOP ?= 0 | ||||||
|  | ifeq ($(SRV_DESKTOP), 1) | ||||||
|  | CFLAGS		+= -DSRV_DESKTOP | ||||||
|  | SRV_DESKTOP = 1 | ||||||
|  | endif | ||||||
|  | 
 | ||||||
| APP_ARCHIVE ?= 0 | APP_ARCHIVE ?= 0 | ||||||
| ifeq ($(APP_NFC), 1) | ifeq ($(APP_NFC), 1) | ||||||
| CFLAGS		+= -DAPP_ARCHIVE | CFLAGS		+= -DAPP_ARCHIVE | ||||||
|  | |||||||
							
								
								
									
										128
									
								
								applications/desktop/desktop.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								applications/desktop/desktop.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,128 @@ | |||||||
|  | #include "desktop_i.h" | ||||||
|  | #include "applications/dolphin/dolphin.h" | ||||||
|  | 
 | ||||||
|  | static void desktop_lock_icon_callback(Canvas* canvas, void* context) { | ||||||
|  |     furi_assert(canvas); | ||||||
|  |     canvas_draw_icon(canvas, 0, 0, &I_Lock_8x8); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool desktop_custom_event_callback(void* context, uint32_t event) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  |     return scene_manager_handle_custom_event(desktop->scene_manager, event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool desktop_back_event_callback(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  |     return scene_manager_handle_back_event(desktop->scene_manager); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Desktop* desktop_alloc() { | ||||||
|  |     Desktop* desktop = furi_alloc(sizeof(Desktop)); | ||||||
|  | 
 | ||||||
|  |     desktop->menu_vm = furi_record_open("menu"); | ||||||
|  |     desktop->gui = furi_record_open("gui"); | ||||||
|  |     desktop->scene_thread = furi_thread_alloc(); | ||||||
|  |     desktop->view_dispatcher = view_dispatcher_alloc(); | ||||||
|  |     desktop->scene_manager = scene_manager_alloc(&desktop_scene_handlers, desktop); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_enable_queue(desktop->view_dispatcher); | ||||||
|  |     view_dispatcher_attach_to_gui( | ||||||
|  |         desktop->view_dispatcher, desktop->gui, ViewDispatcherTypeWindow); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_set_event_callback_context(desktop->view_dispatcher, desktop); | ||||||
|  |     view_dispatcher_set_custom_event_callback( | ||||||
|  |         desktop->view_dispatcher, desktop_custom_event_callback); | ||||||
|  |     view_dispatcher_set_navigation_event_callback( | ||||||
|  |         desktop->view_dispatcher, desktop_back_event_callback); | ||||||
|  | 
 | ||||||
|  |     desktop->main_view = desktop_main_alloc(); | ||||||
|  |     desktop->lock_menu = desktop_lock_menu_alloc(); | ||||||
|  |     desktop->locked_view = desktop_locked_alloc(); | ||||||
|  |     desktop->debug_view = desktop_debug_alloc(); | ||||||
|  |     desktop->first_start_view = desktop_first_start_alloc(); | ||||||
|  |     desktop->hw_mismatch_view = desktop_hw_mismatch_alloc(); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_add_view( | ||||||
|  |         desktop->view_dispatcher, DesktopViewMain, desktop_main_get_view(desktop->main_view)); | ||||||
|  |     view_dispatcher_add_view( | ||||||
|  |         desktop->view_dispatcher, | ||||||
|  |         DesktopViewLockMenu, | ||||||
|  |         desktop_lock_menu_get_view(desktop->lock_menu)); | ||||||
|  |     view_dispatcher_add_view( | ||||||
|  |         desktop->view_dispatcher, DesktopViewDebug, desktop_debug_get_view(desktop->debug_view)); | ||||||
|  |     view_dispatcher_add_view( | ||||||
|  |         desktop->view_dispatcher, | ||||||
|  |         DesktopViewLocked, | ||||||
|  |         desktop_locked_get_view(desktop->locked_view)); | ||||||
|  |     view_dispatcher_add_view( | ||||||
|  |         desktop->view_dispatcher, | ||||||
|  |         DesktopViewFirstStart, | ||||||
|  |         desktop_first_start_get_view(desktop->first_start_view)); | ||||||
|  |     view_dispatcher_add_view( | ||||||
|  |         desktop->view_dispatcher, | ||||||
|  |         DesktopViewHwMismatch, | ||||||
|  |         desktop_hw_mismatch_get_view(desktop->hw_mismatch_view)); | ||||||
|  | 
 | ||||||
|  |     // Lock icon
 | ||||||
|  |     desktop->lock_viewport = view_port_alloc(); | ||||||
|  |     view_port_set_width(desktop->lock_viewport, icon_get_width(&I_Lock_8x8)); | ||||||
|  |     view_port_draw_callback_set(desktop->lock_viewport, desktop_lock_icon_callback, desktop); | ||||||
|  |     view_port_enabled_set(desktop->lock_viewport, false); | ||||||
|  |     gui_add_view_port(desktop->gui, desktop->lock_viewport, GuiLayerStatusBarLeft); | ||||||
|  | 
 | ||||||
|  |     return desktop; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_free(Desktop* desktop) { | ||||||
|  |     furi_assert(desktop); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewMain); | ||||||
|  |     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewLockMenu); | ||||||
|  |     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewLocked); | ||||||
|  |     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewDebug); | ||||||
|  |     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewFirstStart); | ||||||
|  |     view_dispatcher_remove_view(desktop->view_dispatcher, DesktopViewHwMismatch); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_free(desktop->view_dispatcher); | ||||||
|  |     scene_manager_free(desktop->scene_manager); | ||||||
|  | 
 | ||||||
|  |     desktop_main_free(desktop->main_view); | ||||||
|  |     desktop_lock_menu_free(desktop->lock_menu); | ||||||
|  |     desktop_locked_free(desktop->locked_view); | ||||||
|  |     desktop_debug_free(desktop->debug_view); | ||||||
|  |     desktop_first_start_free(desktop->first_start_view); | ||||||
|  |     desktop_hw_mismatch_free(desktop->hw_mismatch_view); | ||||||
|  | 
 | ||||||
|  |     furi_record_close("gui"); | ||||||
|  |     desktop->gui = NULL; | ||||||
|  | 
 | ||||||
|  |     furi_thread_free(desktop->scene_thread); | ||||||
|  | 
 | ||||||
|  |     furi_record_close("menu"); | ||||||
|  |     desktop->menu_vm = NULL; | ||||||
|  | 
 | ||||||
|  |     free(desktop); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int32_t desktop_srv(void* p) { | ||||||
|  |     Desktop* desktop = desktop_alloc(); | ||||||
|  |     Dolphin* dolphin = furi_record_open("dolphin"); | ||||||
|  | 
 | ||||||
|  |     if(dolphin_load(dolphin)) { | ||||||
|  |         scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); | ||||||
|  |     } else { | ||||||
|  |         scene_manager_next_scene(desktop->scene_manager, DesktopSceneFirstStart); | ||||||
|  |     } | ||||||
|  |     furi_record_close("dolphin"); | ||||||
|  | 
 | ||||||
|  |     if(!furi_hal_version_do_i_belong_here()) { | ||||||
|  |         scene_manager_next_scene(desktop->scene_manager, DesktopSceneHwMismatch); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_run(desktop->view_dispatcher); | ||||||
|  |     desktop_free(desktop); | ||||||
|  | 
 | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
							
								
								
									
										3
									
								
								applications/desktop/desktop.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								applications/desktop/desktop.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,3 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | typedef struct Desktop Desktop; | ||||||
							
								
								
									
										59
									
								
								applications/desktop/desktop_i.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										59
									
								
								applications/desktop/desktop_i.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,59 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <furi.h> | ||||||
|  | #include <furi-hal.h> | ||||||
|  | #include <menu/menu.h> | ||||||
|  | #include <gui/gui.h> | ||||||
|  | #include <gui/view_dispatcher.h> | ||||||
|  | #include <gui/scene_manager.h> | ||||||
|  | #include <assets_icons.h> | ||||||
|  | 
 | ||||||
|  | #include "desktop.h" | ||||||
|  | 
 | ||||||
|  | #include "views/desktop_main.h" | ||||||
|  | #include "views/desktop_first_start.h" | ||||||
|  | #include "views/desktop_hw_mismatch.h" | ||||||
|  | #include "views/desktop_lock_menu.h" | ||||||
|  | #include "views/desktop_locked.h" | ||||||
|  | #include "views/desktop_debug.h" | ||||||
|  | #include "scenes/desktop_scene.h" | ||||||
|  | 
 | ||||||
|  | #include "desktop/desktop_settings/desktop_settings.h" | ||||||
|  | 
 | ||||||
|  | #define HINT_TIMEOUT_L 2 | ||||||
|  | #define HINT_TIMEOUT_H 11 | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     DesktopViewMain, | ||||||
|  |     DesktopViewLockMenu, | ||||||
|  |     DesktopViewLocked, | ||||||
|  |     DesktopViewDebug, | ||||||
|  |     DesktopViewFirstStart, | ||||||
|  |     DesktopViewHwMismatch, | ||||||
|  |     DesktopViewTotal, | ||||||
|  | } DesktopViewEnum; | ||||||
|  | 
 | ||||||
|  | struct Desktop { | ||||||
|  |     // Menu
 | ||||||
|  |     ValueMutex* menu_vm; | ||||||
|  |     // Scene
 | ||||||
|  |     FuriThread* scene_thread; | ||||||
|  |     // GUI
 | ||||||
|  |     Gui* gui; | ||||||
|  |     ViewDispatcher* view_dispatcher; | ||||||
|  |     SceneManager* scene_manager; | ||||||
|  | 
 | ||||||
|  |     DesktopFirstStartView* first_start_view; | ||||||
|  |     DesktopHwMismatchView* hw_mismatch_view; | ||||||
|  |     DesktopMainView* main_view; | ||||||
|  |     DesktopLockMenuView* lock_menu; | ||||||
|  |     DesktopLockedView* locked_view; | ||||||
|  |     DesktopDebugView* debug_view; | ||||||
|  |     DesktopSettings settings; | ||||||
|  | 
 | ||||||
|  |     ViewPort* lock_viewport; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | Desktop* desktop_alloc(); | ||||||
|  | 
 | ||||||
|  | void desktop_free(Desktop* desktop); | ||||||
							
								
								
									
										49
									
								
								applications/desktop/desktop_settings/desktop_settings.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								applications/desktop/desktop_settings/desktop_settings.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,49 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include <file-worker.h> | ||||||
|  | #include "desktop_settings.h" | ||||||
|  | 
 | ||||||
|  | #define DESKTOP_SETTINGS_TAG "Desktop settings" | ||||||
|  | #define DESKTOP_SETTINGS_PATH "/int/desktop.settings" | ||||||
|  | 
 | ||||||
|  | bool desktop_settings_load(DesktopSettings* desktop_settings) { | ||||||
|  |     furi_assert(desktop_settings); | ||||||
|  |     bool file_loaded = false; | ||||||
|  |     DesktopSettings settings = {}; | ||||||
|  | 
 | ||||||
|  |     FURI_LOG_I(DESKTOP_SETTINGS_TAG, "Loading settings from \"%s\"", DESKTOP_SETTINGS_PATH); | ||||||
|  |     FileWorker* file_worker = file_worker_alloc(true); | ||||||
|  |     if(file_worker_open(file_worker, DESKTOP_SETTINGS_PATH, FSAM_READ, FSOM_OPEN_EXISTING)) { | ||||||
|  |         if(file_worker_read(file_worker, &settings, sizeof(settings))) { | ||||||
|  |             file_loaded = true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     file_worker_free(file_worker); | ||||||
|  | 
 | ||||||
|  |     if(file_loaded) { | ||||||
|  |         if(settings.version != DESKTOP_SETTINGS_VER) { | ||||||
|  |             FURI_LOG_E(DESKTOP_SETTINGS_TAG, "Settings version mismatch"); | ||||||
|  |         } else { | ||||||
|  |             osKernelLock(); | ||||||
|  |             *desktop_settings = settings; | ||||||
|  |             osKernelUnlock(); | ||||||
|  |         } | ||||||
|  |     } else { | ||||||
|  |         FURI_LOG_E(DESKTOP_SETTINGS_TAG, "Settings load failed"); | ||||||
|  |     } | ||||||
|  |     return file_loaded; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool desktop_settings_save(DesktopSettings* desktop_settings) { | ||||||
|  |     furi_assert(desktop_settings); | ||||||
|  |     bool result = false; | ||||||
|  | 
 | ||||||
|  |     FileWorker* file_worker = file_worker_alloc(true); | ||||||
|  |     if(file_worker_open(file_worker, DESKTOP_SETTINGS_PATH, FSAM_WRITE, FSOM_OPEN_ALWAYS)) { | ||||||
|  |         if(file_worker_write(file_worker, desktop_settings, sizeof(DesktopSettings))) { | ||||||
|  |             FURI_LOG_I(DESKTOP_SETTINGS_TAG, "Settings saved to \"%s\"", DESKTOP_SETTINGS_PATH); | ||||||
|  |             result = true; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     file_worker_free(file_worker); | ||||||
|  |     return result; | ||||||
|  | } | ||||||
							
								
								
									
										15
									
								
								applications/desktop/desktop_settings/desktop_settings.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								applications/desktop/desktop_settings/desktop_settings.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <stdint.h> | ||||||
|  | #include <stdbool.h> | ||||||
|  | 
 | ||||||
|  | #define DESKTOP_SETTINGS_VER (0) | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t version; | ||||||
|  |     uint16_t favorite; | ||||||
|  | } DesktopSettings; | ||||||
|  | 
 | ||||||
|  | bool desktop_settings_load(DesktopSettings* desktop_settings); | ||||||
|  | 
 | ||||||
|  | bool desktop_settings_save(DesktopSettings* desktop_settings); | ||||||
							
								
								
									
										65
									
								
								applications/desktop/desktop_settings/desktop_settings_app.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								applications/desktop/desktop_settings/desktop_settings_app.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,65 @@ | |||||||
|  | #include "desktop_settings_app.h" | ||||||
|  | 
 | ||||||
|  | static bool desktop_settings_custom_event_callback(void* context, uint32_t event) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     DesktopSettingsApp* app = context; | ||||||
|  |     return scene_manager_handle_custom_event(app->scene_manager, event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static bool desktop_settings_back_event_callback(void* context) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     DesktopSettingsApp* app = context; | ||||||
|  |     return scene_manager_handle_back_event(app->scene_manager); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DesktopSettingsApp* desktop_settings_app_alloc() { | ||||||
|  |     DesktopSettingsApp* app = furi_alloc(sizeof(DesktopSettingsApp)); | ||||||
|  | 
 | ||||||
|  |     app->settings.version = DESKTOP_SETTINGS_VER; | ||||||
|  |     desktop_settings_load(&app->settings); | ||||||
|  | 
 | ||||||
|  |     app->gui = furi_record_open("gui"); | ||||||
|  |     app->view_dispatcher = view_dispatcher_alloc(); | ||||||
|  |     app->scene_manager = scene_manager_alloc(&desktop_settings_scene_handlers, app); | ||||||
|  |     view_dispatcher_enable_queue(app->view_dispatcher); | ||||||
|  |     view_dispatcher_set_event_callback_context(app->view_dispatcher, app); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_set_custom_event_callback( | ||||||
|  |         app->view_dispatcher, desktop_settings_custom_event_callback); | ||||||
|  |     view_dispatcher_set_navigation_event_callback( | ||||||
|  |         app->view_dispatcher, desktop_settings_back_event_callback); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen); | ||||||
|  | 
 | ||||||
|  |     app->submenu = submenu_alloc(); | ||||||
|  |     view_dispatcher_add_view( | ||||||
|  |         app->view_dispatcher, DesktopSettingsAppViewMain, submenu_get_view(app->submenu)); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_add_view( | ||||||
|  |         app->view_dispatcher, DesktopSettingsAppViewFavorite, submenu_get_view(app->submenu)); | ||||||
|  | 
 | ||||||
|  |     scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneStart); | ||||||
|  |     return app; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_settings_app_free(DesktopSettingsApp* app) { | ||||||
|  |     furi_assert(app); | ||||||
|  |     // Variable item list
 | ||||||
|  |     view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewMain); | ||||||
|  |     view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewFavorite); | ||||||
|  |     submenu_free(app->submenu); | ||||||
|  |     // View dispatcher
 | ||||||
|  |     view_dispatcher_free(app->view_dispatcher); | ||||||
|  |     scene_manager_free(app->scene_manager); | ||||||
|  |     // Records
 | ||||||
|  |     furi_record_close("gui"); | ||||||
|  |     free(app); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | extern int32_t desktop_settings_app(void* p) { | ||||||
|  |     DesktopSettingsApp* app = desktop_settings_app_alloc(); | ||||||
|  |     view_dispatcher_run(app->view_dispatcher); | ||||||
|  |     desktop_settings_save(&app->settings); | ||||||
|  |     desktop_settings_app_free(app); | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
							
								
								
									
										25
									
								
								applications/desktop/desktop_settings/desktop_settings_app.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								applications/desktop/desktop_settings/desktop_settings_app.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,25 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <furi.h> | ||||||
|  | #include <gui/gui.h> | ||||||
|  | #include <gui/view.h> | ||||||
|  | #include <gui/view_dispatcher.h> | ||||||
|  | #include <gui/scene_manager.h> | ||||||
|  | #include <gui/modules/submenu.h> | ||||||
|  | 
 | ||||||
|  | #include "desktop_settings.h" | ||||||
|  | #include "scenes/desktop_settings_scene.h" | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     DesktopSettingsAppViewMain, | ||||||
|  |     DesktopSettingsAppViewFavorite, | ||||||
|  | } DesktopSettingsAppView; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     DesktopSettings settings; | ||||||
|  |     Gui* gui; | ||||||
|  |     SceneManager* scene_manager; | ||||||
|  |     ViewDispatcher* view_dispatcher; | ||||||
|  |     Submenu* submenu; | ||||||
|  | 
 | ||||||
|  | } DesktopSettingsApp; | ||||||
| @ -0,0 +1,30 @@ | |||||||
|  | #include "desktop_settings_scene.h" | ||||||
|  | 
 | ||||||
|  | // Generate scene on_enter handlers array
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, | ||||||
|  | void (*const desktop_settings_on_enter_handlers[])(void*) = { | ||||||
|  | #include "desktop_settings_scene_config.h" | ||||||
|  | }; | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | // Generate scene on_event handlers array
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, | ||||||
|  | bool (*const desktop_settings_on_event_handlers[])(void* context, SceneManagerEvent event) = { | ||||||
|  | #include "desktop_settings_scene_config.h" | ||||||
|  | }; | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | // Generate scene on_exit handlers array
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, | ||||||
|  | void (*const desktop_settings_on_exit_handlers[])(void* context) = { | ||||||
|  | #include "desktop_settings_scene_config.h" | ||||||
|  | }; | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | // Initialize scene handlers configuration structure
 | ||||||
|  | const SceneManagerHandlers desktop_settings_scene_handlers = { | ||||||
|  |     .on_enter_handlers = desktop_settings_on_enter_handlers, | ||||||
|  |     .on_event_handlers = desktop_settings_on_event_handlers, | ||||||
|  |     .on_exit_handlers = desktop_settings_on_exit_handlers, | ||||||
|  |     .scene_num = DesktopSettingsAppSceneNum, | ||||||
|  | }; | ||||||
| @ -0,0 +1,29 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <gui/scene_manager.h> | ||||||
|  | 
 | ||||||
|  | // Generate scene id and total number
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) DesktopSettingsAppScene##id, | ||||||
|  | typedef enum { | ||||||
|  | #include "desktop_settings_scene_config.h" | ||||||
|  |     DesktopSettingsAppSceneNum, | ||||||
|  | } DesktopSettingsAppScene; | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | extern const SceneManagerHandlers desktop_settings_scene_handlers; | ||||||
|  | 
 | ||||||
|  | // Generate scene on_enter handlers declaration
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); | ||||||
|  | #include "desktop_settings_scene_config.h" | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | // Generate scene on_event handlers declaration
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) \ | ||||||
|  |     bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); | ||||||
|  | #include "desktop_settings_scene_config.h" | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | // Generate scene on_exit handlers declaration
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); | ||||||
|  | #include "desktop_settings_scene_config.h" | ||||||
|  | #undef ADD_SCENE | ||||||
| @ -0,0 +1,2 @@ | |||||||
|  | ADD_SCENE(desktop_settings, start, Start) | ||||||
|  | ADD_SCENE(desktop_settings, favorite, Favorite) | ||||||
| @ -0,0 +1,47 @@ | |||||||
|  | #include "../desktop_settings_app.h" | ||||||
|  | #include "applications.h" | ||||||
|  | 
 | ||||||
|  | static void desktop_settings_scene_favorite_submenu_callback(void* context, uint32_t index) { | ||||||
|  |     DesktopSettingsApp* app = context; | ||||||
|  |     view_dispatcher_send_custom_event(app->view_dispatcher, index); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_settings_scene_favorite_on_enter(void* context) { | ||||||
|  |     DesktopSettingsApp* app = context; | ||||||
|  |     Submenu* submenu = app->submenu; | ||||||
|  |     submenu_clean(submenu); | ||||||
|  | 
 | ||||||
|  |     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); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     submenu_set_header(app->submenu, "Quick access app:"); | ||||||
|  |     submenu_set_selected_item(app->submenu, app->settings.favorite); | ||||||
|  |     view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewFavorite); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     DesktopSettingsApp* app = context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         switch(event.event) { | ||||||
|  |         default: | ||||||
|  |             app->settings.favorite = event.event; | ||||||
|  |             scene_manager_previous_scene(app->scene_manager); | ||||||
|  |             consumed = true; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_settings_scene_favorite_on_exit(void* context) { | ||||||
|  |     DesktopSettingsApp* app = context; | ||||||
|  |     submenu_clean(app->submenu); | ||||||
|  | } | ||||||
							
								
								
									
										53
									
								
								applications/desktop/desktop_settings/scenes/desktop_settings_scene_start.c
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										53
									
								
								applications/desktop/desktop_settings/scenes/desktop_settings_scene_start.c
									
									
									
									
									
										Executable file
									
								
							| @ -0,0 +1,53 @@ | |||||||
|  | #include "../desktop_settings_app.h" | ||||||
|  | #include "applications.h" | ||||||
|  | 
 | ||||||
|  | enum DesktopSettingsStartSubmenuIndex { | ||||||
|  |     DesktopSettingsStartSubmenuIndexFavorite, | ||||||
|  |     DesktopSettingsStartSubmenuIndexPinSetup, | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | static void desktop_settings_scene_start_submenu_callback(void* context, uint32_t index) { | ||||||
|  |     DesktopSettingsApp* app = context; | ||||||
|  |     view_dispatcher_send_custom_event(app->view_dispatcher, index); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_settings_scene_start_on_enter(void* context) { | ||||||
|  |     DesktopSettingsApp* app = context; | ||||||
|  |     Submenu* submenu = app->submenu; | ||||||
|  | 
 | ||||||
|  |     submenu_add_item( | ||||||
|  |         submenu, | ||||||
|  |         "Favorite App", | ||||||
|  |         DesktopSettingsStartSubmenuIndexFavorite, | ||||||
|  |         desktop_settings_scene_start_submenu_callback, | ||||||
|  |         app); | ||||||
|  | 
 | ||||||
|  |     submenu_add_item( | ||||||
|  |         submenu, | ||||||
|  |         "PIN Setup", | ||||||
|  |         DesktopSettingsStartSubmenuIndexPinSetup, | ||||||
|  |         desktop_settings_scene_start_submenu_callback, | ||||||
|  |         app); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewMain); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool desktop_settings_scene_start_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     DesktopSettingsApp* app = context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         switch(event.event) { | ||||||
|  |         case DesktopSettingsStartSubmenuIndexFavorite: | ||||||
|  |             scene_manager_next_scene(app->scene_manager, DesktopSettingsAppViewFavorite); | ||||||
|  |             consumed = true; | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_settings_scene_start_on_exit(void* context) { | ||||||
|  |     DesktopSettingsApp* app = context; | ||||||
|  |     submenu_clean(app->submenu); | ||||||
|  | } | ||||||
							
								
								
									
										30
									
								
								applications/desktop/scenes/desktop_scene.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										30
									
								
								applications/desktop/scenes/desktop_scene.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,30 @@ | |||||||
|  | #include "desktop_scene.h" | ||||||
|  | 
 | ||||||
|  | // Generate scene on_enter handlers array
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter, | ||||||
|  | void (*const desktop_on_enter_handlers[])(void*) = { | ||||||
|  | #include "desktop_scene_config.h" | ||||||
|  | }; | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | // Generate scene on_event handlers array
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event, | ||||||
|  | bool (*const desktop_on_event_handlers[])(void* context, SceneManagerEvent event) = { | ||||||
|  | #include "desktop_scene_config.h" | ||||||
|  | }; | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | // Generate scene on_exit handlers array
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit, | ||||||
|  | void (*const desktop_on_exit_handlers[])(void* context) = { | ||||||
|  | #include "desktop_scene_config.h" | ||||||
|  | }; | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | // Initialize scene handlers configuration structure
 | ||||||
|  | const SceneManagerHandlers desktop_scene_handlers = { | ||||||
|  |     .on_enter_handlers = desktop_on_enter_handlers, | ||||||
|  |     .on_event_handlers = desktop_on_event_handlers, | ||||||
|  |     .on_exit_handlers = desktop_on_exit_handlers, | ||||||
|  |     .scene_num = DesktopSceneNum, | ||||||
|  | }; | ||||||
							
								
								
									
										29
									
								
								applications/desktop/scenes/desktop_scene.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								applications/desktop/scenes/desktop_scene.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,29 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <gui/scene_manager.h> | ||||||
|  | 
 | ||||||
|  | // Generate scene id and total number
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) DesktopScene##id, | ||||||
|  | typedef enum { | ||||||
|  | #include "desktop_scene_config.h" | ||||||
|  |     DesktopSceneNum, | ||||||
|  | } DesktopScene; | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | extern const SceneManagerHandlers desktop_scene_handlers; | ||||||
|  | 
 | ||||||
|  | // Generate scene on_enter handlers declaration
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*); | ||||||
|  | #include "desktop_scene_config.h" | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | // Generate scene on_event handlers declaration
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) \ | ||||||
|  |     bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event); | ||||||
|  | #include "desktop_scene_config.h" | ||||||
|  | #undef ADD_SCENE | ||||||
|  | 
 | ||||||
|  | // Generate scene on_exit handlers declaration
 | ||||||
|  | #define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context); | ||||||
|  | #include "desktop_scene_config.h" | ||||||
|  | #undef ADD_SCENE | ||||||
							
								
								
									
										6
									
								
								applications/desktop/scenes/desktop_scene_config.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								applications/desktop/scenes/desktop_scene_config.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,6 @@ | |||||||
|  | ADD_SCENE(desktop, main, Main) | ||||||
|  | ADD_SCENE(desktop, lock_menu, LockMenu) | ||||||
|  | ADD_SCENE(desktop, locked, Locked) | ||||||
|  | ADD_SCENE(desktop, debug, Debug) | ||||||
|  | ADD_SCENE(desktop, first_start, FirstStart) | ||||||
|  | ADD_SCENE(desktop, hw_mismatch, HwMismatch) | ||||||
							
								
								
									
										62
									
								
								applications/desktop/scenes/desktop_scene_debug.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								applications/desktop/scenes/desktop_scene_debug.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,62 @@ | |||||||
|  | #include "../desktop_i.h" | ||||||
|  | #include "../views/desktop_debug.h" | ||||||
|  | #include "applications/dolphin/dolphin.h" | ||||||
|  | #include "applications/dolphin/helpers/dolphin_deed.h" | ||||||
|  | 
 | ||||||
|  | void desktop_scene_debug_callback(DesktopDebugEvent event, void* context) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  |     view_dispatcher_send_custom_event(desktop->view_dispatcher, event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const 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, DesktopViewDebug); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const bool desktop_scene_debug_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  |     Dolphin* dolphin = furi_record_open("dolphin"); | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         switch(event.event) { | ||||||
|  |         case DesktopDebugEventExit: | ||||||
|  |             scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); | ||||||
|  |             dolphin_save(dolphin); | ||||||
|  |             consumed = true; | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         case DesktopDebugEventDeed: | ||||||
|  |             dolphin_deed(dolphin, DolphinDeedIButtonEmulate); | ||||||
|  |             desktop_debug_get_dolphin_data(desktop->debug_view); | ||||||
|  |             consumed = true; | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         case DesktopDebugEventWrongDeed: | ||||||
|  |             dolphin_deed(dolphin, DolphinDeedWrong); | ||||||
|  |             desktop_debug_get_dolphin_data(desktop->debug_view); | ||||||
|  |             consumed = true; | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         case DesktopDebugEventSaveState: | ||||||
|  |             dolphin_save(dolphin); | ||||||
|  |             consumed = true; | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     furi_record_close("dolphin"); | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void desktop_scene_debug_on_exit(void* context) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  |     desktop_debug_reset_screen_idx(desktop->debug_view); | ||||||
|  | } | ||||||
							
								
								
									
										43
									
								
								applications/desktop/scenes/desktop_scene_first_start.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								applications/desktop/scenes/desktop_scene_first_start.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | |||||||
|  | #include "../desktop_i.h" | ||||||
|  | #include "../views/desktop_first_start.h" | ||||||
|  | #include "applications/dolphin/dolphin.h" | ||||||
|  | 
 | ||||||
|  | void desktop_scene_first_start_callback(DesktopFirstStartEvent event, void* context) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  |     view_dispatcher_send_custom_event(desktop->view_dispatcher, event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void desktop_scene_first_start_on_enter(void* context) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  |     DesktopFirstStartView* first_start_view = desktop->first_start_view; | ||||||
|  | 
 | ||||||
|  |     desktop_first_start_set_callback( | ||||||
|  |         first_start_view, desktop_scene_first_start_callback, desktop); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewFirstStart); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const bool desktop_scene_first_start_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         switch(event.event) { | ||||||
|  |         case DesktopFirstStartCompleted: | ||||||
|  |             scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); | ||||||
|  |             consumed = true; | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void desktop_scene_first_start_on_exit(void* context) { | ||||||
|  |     // Desktop* desktop = (Desktop*)context;
 | ||||||
|  |     Dolphin* dolphin = furi_record_open("dolphin"); | ||||||
|  |     dolphin_save(dolphin); | ||||||
|  |     furi_record_close("dolphin"); | ||||||
|  | } | ||||||
							
								
								
									
										37
									
								
								applications/desktop/scenes/desktop_scene_hw_mismatch.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								applications/desktop/scenes/desktop_scene_hw_mismatch.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,37 @@ | |||||||
|  | #include "../desktop_i.h" | ||||||
|  | #include "../views/desktop_hw_mismatch.h" | ||||||
|  | 
 | ||||||
|  | void desktop_scene_hw_mismatch_callback(DesktopHwMismatchEvent event, void* context) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  |     view_dispatcher_send_custom_event(desktop->view_dispatcher, event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void desktop_scene_hw_mismatch_on_enter(void* context) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  | 
 | ||||||
|  |     desktop_hw_mismatch_set_callback( | ||||||
|  |         desktop->hw_mismatch_view, desktop_scene_hw_mismatch_callback, desktop); | ||||||
|  |     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewHwMismatch); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const bool desktop_scene_hw_mismatch_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         switch(event.event) { | ||||||
|  |         case DesktopHwMismatchEventExit: | ||||||
|  |             scene_manager_previous_scene(desktop->scene_manager); | ||||||
|  |             consumed = true; | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void desktop_scene_hw_mismatch_on_exit(void* context) { | ||||||
|  |     // Desktop* desktop = (Desktop*)context;
 | ||||||
|  | } | ||||||
							
								
								
									
										42
									
								
								applications/desktop/scenes/desktop_scene_lock_menu.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								applications/desktop/scenes/desktop_scene_lock_menu.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | |||||||
|  | #include "../desktop_i.h" | ||||||
|  | #include "../views/desktop_lock_menu.h" | ||||||
|  | 
 | ||||||
|  | void desktop_scene_lock_menu_callback(DesktopLockMenuEvent event, void* context) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  |     view_dispatcher_send_custom_event(desktop->view_dispatcher, event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void desktop_scene_lock_menu_on_enter(void* context) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  | 
 | ||||||
|  |     desktop_lock_menu_set_callback(desktop->lock_menu, desktop_scene_lock_menu_callback, desktop); | ||||||
|  |     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewLockMenu); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const bool desktop_scene_lock_menu_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         switch(event.event) { | ||||||
|  |         case DesktopLockMenuEventLock: | ||||||
|  |             scene_manager_next_scene(desktop->scene_manager, DesktopSceneLocked); | ||||||
|  |             consumed = true; | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         case DesktopLockMenuEventExit: | ||||||
|  |             scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); | ||||||
|  |             consumed = true; | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void desktop_scene_lock_menu_on_exit(void* context) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  |     desktop_lock_menu_reset_idx(desktop->lock_menu); | ||||||
|  | } | ||||||
							
								
								
									
										51
									
								
								applications/desktop/scenes/desktop_scene_locked.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								applications/desktop/scenes/desktop_scene_locked.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,51 @@ | |||||||
|  | #include "../desktop_i.h" | ||||||
|  | #include "../views/desktop_locked.h" | ||||||
|  | 
 | ||||||
|  | void desktop_scene_locked_callback(DesktopLockedEvent event, void* context) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  |     view_dispatcher_send_custom_event(desktop->view_dispatcher, event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void desktop_scene_locked_on_enter(void* context) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  |     DesktopLockedView* locked_view = desktop->locked_view; | ||||||
|  | 
 | ||||||
|  |     desktop_locked_set_callback(locked_view, desktop_scene_locked_callback, desktop); | ||||||
|  |     desktop_locked_reset_door_pos(locked_view); | ||||||
|  |     desktop_locked_update_hint_timeout(locked_view); | ||||||
|  | 
 | ||||||
|  |     view_port_enabled_set(desktop->lock_viewport, true); | ||||||
|  |     osTimerStart(locked_view->timer, 63); | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewLocked); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const bool desktop_scene_locked_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  | 
 | ||||||
|  |     bool consumed = false; | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         switch(event.event) { | ||||||
|  |         case DesktopLockedEventUnlock: | ||||||
|  |             scene_manager_set_scene_state( | ||||||
|  |                 desktop->scene_manager, DesktopSceneMain, DesktopMainEventUnlocked); | ||||||
|  |             scene_manager_next_scene(desktop->scene_manager, DesktopSceneMain); | ||||||
|  |             consumed = true; | ||||||
|  |             break; | ||||||
|  |         case DesktopLockedEventUpdate: | ||||||
|  |             desktop_locked_manage_redraw(desktop->locked_view); | ||||||
|  |             consumed = true; | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void desktop_scene_locked_on_exit(void* context) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  |     DesktopLockedView* locked_view = desktop->locked_view; | ||||||
|  |     desktop_locked_reset_counter(desktop->locked_view); | ||||||
|  |     osTimerStop(locked_view->timer); | ||||||
|  | } | ||||||
							
								
								
									
										88
									
								
								applications/desktop/scenes/desktop_scene_main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										88
									
								
								applications/desktop/scenes/desktop_scene_main.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,88 @@ | |||||||
|  | #include "../desktop_i.h" | ||||||
|  | #include "../views/desktop_main.h" | ||||||
|  | #include "applications.h" | ||||||
|  | #define MAIN_VIEW_DEFAULT (0UL) | ||||||
|  | 
 | ||||||
|  | static void desktop_switch_to_app(Desktop* desktop, const FlipperApplication* flipper_app) { | ||||||
|  |     furi_assert(desktop); | ||||||
|  |     furi_assert(flipper_app); | ||||||
|  |     furi_assert(flipper_app->app); | ||||||
|  |     furi_assert(flipper_app->name); | ||||||
|  | 
 | ||||||
|  |     if(furi_thread_get_state(desktop->scene_thread) != FuriThreadStateStopped) { | ||||||
|  |         FURI_LOG_E("Desktop", "Thread is already running"); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     furi_thread_set_name(desktop->scene_thread, flipper_app->name); | ||||||
|  |     furi_thread_set_stack_size(desktop->scene_thread, flipper_app->stack_size); | ||||||
|  |     furi_thread_set_callback(desktop->scene_thread, flipper_app->app); | ||||||
|  | 
 | ||||||
|  |     furi_thread_start(desktop->scene_thread); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_scene_main_callback(DesktopMainEvent event, void* context) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  |     view_dispatcher_send_custom_event(desktop->view_dispatcher, event); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void desktop_scene_main_on_enter(void* context) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  |     DesktopMainView* main_view = desktop->main_view; | ||||||
|  | 
 | ||||||
|  |     desktop_main_set_callback(main_view, desktop_scene_main_callback, desktop); | ||||||
|  |     view_port_enabled_set(desktop->lock_viewport, false); | ||||||
|  | 
 | ||||||
|  |     if(scene_manager_get_scene_state(desktop->scene_manager, DesktopSceneMain) == | ||||||
|  |        DesktopMainEventUnlocked) { | ||||||
|  |         desktop_main_unlocked(desktop->main_view); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     view_dispatcher_switch_to_view(desktop->view_dispatcher, DesktopViewMain); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const bool desktop_scene_main_on_event(void* context, SceneManagerEvent event) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  |     bool consumed = false; | ||||||
|  | 
 | ||||||
|  |     if(event.type == SceneManagerEventTypeCustom) { | ||||||
|  |         switch(event.event) { | ||||||
|  |         case DesktopMainEventOpenMenu: | ||||||
|  |             with_value_mutex( | ||||||
|  |                 desktop->menu_vm, (Menu * menu) { menu_ok(menu); }); | ||||||
|  |             consumed = true; | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         case DesktopMainEventOpenLockMenu: | ||||||
|  |             scene_manager_next_scene(desktop->scene_manager, DesktopSceneLockMenu); | ||||||
|  |             consumed = true; | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         case DesktopMainEventOpenDebug: | ||||||
|  |             scene_manager_next_scene(desktop->scene_manager, DesktopViewDebug); | ||||||
|  |             consumed = true; | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         case DesktopMainEventOpenArchive: | ||||||
|  |             desktop_switch_to_app(desktop, &FLIPPER_ARCHIVE); | ||||||
|  |             consumed = true; | ||||||
|  |             break; | ||||||
|  |         case DesktopMainEventOpenFavorite: | ||||||
|  |             desktop_settings_load(&desktop->settings); | ||||||
|  |             desktop_switch_to_app(desktop, &FLIPPER_APPS[desktop->settings.favorite]); | ||||||
|  |             consumed = true; | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return consumed; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const void desktop_scene_main_on_exit(void* context) { | ||||||
|  |     Desktop* desktop = (Desktop*)context; | ||||||
|  |     scene_manager_set_scene_state(desktop->scene_manager, DesktopSceneMain, MAIN_VIEW_DEFAULT); | ||||||
|  |     desktop_main_reset_hint(desktop->main_view); | ||||||
|  | } | ||||||
							
								
								
									
										166
									
								
								applications/desktop/views/desktop_debug.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										166
									
								
								applications/desktop/views/desktop_debug.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,166 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include "../desktop_i.h" | ||||||
|  | #include "desktop_debug.h" | ||||||
|  | 
 | ||||||
|  | #include "applications/dolphin/helpers/dolphin_state.h" | ||||||
|  | #include "applications/dolphin/dolphin.h" | ||||||
|  | 
 | ||||||
|  | void desktop_debug_set_callback( | ||||||
|  |     DesktopDebugView* debug_view, | ||||||
|  |     DesktopDebugViewCallback callback, | ||||||
|  |     void* context) { | ||||||
|  |     furi_assert(debug_view); | ||||||
|  |     furi_assert(callback); | ||||||
|  |     debug_view->callback = callback; | ||||||
|  |     debug_view->context = context; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_debug_render(Canvas* canvas, void* model) { | ||||||
|  |     canvas_clear(canvas); | ||||||
|  |     DesktopDebugViewModel* m = model; | ||||||
|  |     const Version* ver; | ||||||
|  |     char buffer[64]; | ||||||
|  | 
 | ||||||
|  |     static const char* headers[] = {"FW Version info:", "Boot Version info:", "Desktop info:"}; | ||||||
|  | 
 | ||||||
|  |     canvas_set_color(canvas, ColorBlack); | ||||||
|  |     canvas_set_font(canvas, FontPrimary); | ||||||
|  |     canvas_draw_str(canvas, 2, 13, headers[m->screen]); | ||||||
|  |     canvas_set_font(canvas, FontSecondary); | ||||||
|  | 
 | ||||||
|  |     if(m->screen != DesktopViewStatsMeta) { | ||||||
|  |         // Hardware version
 | ||||||
|  |         const char* my_name = furi_hal_version_get_name_ptr(); | ||||||
|  |         snprintf( | ||||||
|  |             buffer, | ||||||
|  |             sizeof(buffer), | ||||||
|  |             "HW: %d.F%dB%dC%d %s", | ||||||
|  |             furi_hal_version_get_hw_version(), | ||||||
|  |             furi_hal_version_get_hw_target(), | ||||||
|  |             furi_hal_version_get_hw_body(), | ||||||
|  |             furi_hal_version_get_hw_connect(), | ||||||
|  |             my_name ? my_name : "Unknown"); | ||||||
|  |         canvas_draw_str(canvas, 5, 23, buffer); | ||||||
|  | 
 | ||||||
|  |         ver = m->screen == DesktopViewStatsBoot ? furi_hal_version_get_boot_version() : | ||||||
|  |                                                   furi_hal_version_get_firmware_version(); | ||||||
|  | 
 | ||||||
|  |         if(!ver) { | ||||||
|  |             canvas_draw_str(canvas, 5, 33, "No info"); | ||||||
|  |             return; | ||||||
|  |         } | ||||||
|  | 
 | ||||||
|  |         snprintf( | ||||||
|  |             buffer, | ||||||
|  |             sizeof(buffer), | ||||||
|  |             "%s [%s]", | ||||||
|  |             version_get_version(ver), | ||||||
|  |             version_get_builddate(ver)); | ||||||
|  |         canvas_draw_str(canvas, 5, 33, buffer); | ||||||
|  | 
 | ||||||
|  |         snprintf( | ||||||
|  |             buffer, | ||||||
|  |             sizeof(buffer), | ||||||
|  |             "%s [%s]", | ||||||
|  |             version_get_githash(ver), | ||||||
|  |             version_get_gitbranchnum(ver)); | ||||||
|  |         canvas_draw_str(canvas, 5, 43, buffer); | ||||||
|  | 
 | ||||||
|  |         snprintf( | ||||||
|  |             buffer, sizeof(buffer), "[%s] %s", version_get_target(ver), version_get_gitbranch(ver)); | ||||||
|  |         canvas_draw_str(canvas, 5, 53, buffer); | ||||||
|  | 
 | ||||||
|  |     } else { | ||||||
|  |         char buffer[64]; | ||||||
|  | 
 | ||||||
|  |         canvas_set_font(canvas, FontSecondary); | ||||||
|  |         snprintf(buffer, 64, "Icounter: %ld", m->icounter); | ||||||
|  |         canvas_draw_str(canvas, 5, 30, buffer); | ||||||
|  |         snprintf(buffer, 64, "Butthurt: %ld", m->butthurt); | ||||||
|  |         canvas_draw_str(canvas, 5, 40, buffer); | ||||||
|  |         canvas_draw_str(canvas, 0, 53, "[< >] icounter value   [ok] save"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | View* desktop_debug_get_view(DesktopDebugView* debug_view) { | ||||||
|  |     furi_assert(debug_view); | ||||||
|  |     return debug_view->view; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool desktop_debug_input(InputEvent* event, void* context) { | ||||||
|  |     furi_assert(event); | ||||||
|  |     furi_assert(context); | ||||||
|  | 
 | ||||||
|  |     DesktopDebugView* debug_view = context; | ||||||
|  | 
 | ||||||
|  |     if(event->type != InputTypeShort) return false; | ||||||
|  |     DesktopViewStatsScreens current = 0; | ||||||
|  |     with_view_model( | ||||||
|  |         debug_view->view, (DesktopDebugViewModel * model) { | ||||||
|  |             if(event->key == InputKeyDown) { | ||||||
|  |                 model->screen = (model->screen + 1) % DesktopViewStatsTotalCount; | ||||||
|  |             } else if(event->key == InputKeyUp) { | ||||||
|  |                 model->screen = ((model->screen - 1) + DesktopViewStatsTotalCount) % | ||||||
|  |                                 DesktopViewStatsTotalCount; | ||||||
|  |             } | ||||||
|  |             current = model->screen; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     if(current == DesktopViewStatsMeta) { | ||||||
|  |         if(event->key == InputKeyLeft) { | ||||||
|  |             debug_view->callback(DesktopDebugEventWrongDeed, debug_view->context); | ||||||
|  |         } else if(event->key == InputKeyRight) { | ||||||
|  |             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) { | ||||||
|  |         debug_view->callback(DesktopDebugEventExit, debug_view->context); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DesktopDebugView* desktop_debug_alloc() { | ||||||
|  |     DesktopDebugView* debug_view = furi_alloc(sizeof(DesktopDebugView)); | ||||||
|  |     debug_view->view = view_alloc(); | ||||||
|  |     view_allocate_model(debug_view->view, ViewModelTypeLocking, sizeof(DesktopDebugViewModel)); | ||||||
|  |     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); | ||||||
|  | 
 | ||||||
|  |     return debug_view; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_debug_free(DesktopDebugView* debug_view) { | ||||||
|  |     furi_assert(debug_view); | ||||||
|  | 
 | ||||||
|  |     view_free(debug_view->view); | ||||||
|  |     free(debug_view); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_debug_get_dolphin_data(DesktopDebugView* debug_view) { | ||||||
|  |     Dolphin* dolphin = furi_record_open("dolphin"); | ||||||
|  |     DolphinDeedWeight stats = dolphin_stats(dolphin); | ||||||
|  |     with_view_model( | ||||||
|  |         debug_view->view, (DesktopDebugViewModel * model) { | ||||||
|  |             model->icounter = stats.icounter; | ||||||
|  |             model->butthurt = stats.butthurt; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     furi_record_close("dolphin"); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_debug_reset_screen_idx(DesktopDebugView* debug_view) { | ||||||
|  |     with_view_model( | ||||||
|  |         debug_view->view, (DesktopDebugViewModel * model) { | ||||||
|  |             model->screen = 0; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
							
								
								
									
										52
									
								
								applications/desktop/views/desktop_debug.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								applications/desktop/views/desktop_debug.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,52 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <gui/gui_i.h> | ||||||
|  | #include <gui/view.h> | ||||||
|  | #include <gui/canvas.h> | ||||||
|  | #include <gui/elements.h> | ||||||
|  | #include <furi.h> | ||||||
|  | #include <storage/storage.h> | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     DesktopDebugEventDeed, | ||||||
|  |     DesktopDebugEventWrongDeed, | ||||||
|  |     DesktopDebugEventSaveState, | ||||||
|  |     DesktopDebugEventExit, | ||||||
|  | } DesktopDebugEvent; | ||||||
|  | 
 | ||||||
|  | typedef struct DesktopDebugView DesktopDebugView; | ||||||
|  | 
 | ||||||
|  | typedef void (*DesktopDebugViewCallback)(DesktopDebugEvent event, void* context); | ||||||
|  | 
 | ||||||
|  | // Debug info
 | ||||||
|  | typedef enum { | ||||||
|  |     DesktopViewStatsFw, | ||||||
|  |     DesktopViewStatsBoot, | ||||||
|  |     DesktopViewStatsMeta, | ||||||
|  |     DesktopViewStatsTotalCount, | ||||||
|  | } DesktopViewStatsScreens; | ||||||
|  | 
 | ||||||
|  | struct DesktopDebugView { | ||||||
|  |     View* view; | ||||||
|  |     DesktopDebugViewCallback callback; | ||||||
|  |     void* context; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint32_t icounter; | ||||||
|  |     uint32_t butthurt; | ||||||
|  |     DesktopViewStatsScreens screen; | ||||||
|  | } DesktopDebugViewModel; | ||||||
|  | 
 | ||||||
|  | void desktop_debug_set_callback( | ||||||
|  |     DesktopDebugView* debug_view, | ||||||
|  |     DesktopDebugViewCallback callback, | ||||||
|  |     void* context); | ||||||
|  | 
 | ||||||
|  | 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); | ||||||
							
								
								
									
										107
									
								
								applications/desktop/views/desktop_first_start.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								applications/desktop/views/desktop_first_start.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,107 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include "../desktop_i.h" | ||||||
|  | #include "desktop_first_start.h" | ||||||
|  | 
 | ||||||
|  | void desktop_first_start_set_callback( | ||||||
|  |     DesktopFirstStartView* first_start_view, | ||||||
|  |     DesktopFirstStartViewCallback callback, | ||||||
|  |     void* context) { | ||||||
|  |     furi_assert(first_start_view); | ||||||
|  |     furi_assert(callback); | ||||||
|  |     first_start_view->callback = callback; | ||||||
|  |     first_start_view->context = context; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_first_start_render(Canvas* canvas, void* model) { | ||||||
|  |     DesktopFirstStartViewModel* m = model; | ||||||
|  | 
 | ||||||
|  |     canvas_clear(canvas); | ||||||
|  |     canvas_set_color(canvas, ColorBlack); | ||||||
|  |     canvas_set_font(canvas, FontSecondary); | ||||||
|  |     uint8_t width = canvas_width(canvas); | ||||||
|  |     uint8_t height = canvas_height(canvas); | ||||||
|  |     const char* my_name = furi_hal_version_get_name_ptr(); | ||||||
|  |     if(m->page == 0) { | ||||||
|  |         canvas_draw_icon(canvas, 0, height - 48, &I_DolphinFirstStart0_70x53); | ||||||
|  |         elements_multiline_text_framed(canvas, 75, 20, "Hey m8,\npress > to\ncontinue"); | ||||||
|  |     } else if(m->page == 1) { | ||||||
|  |         canvas_draw_icon(canvas, 0, height - 48, &I_DolphinFirstStart1_59x53); | ||||||
|  |         elements_multiline_text_framed(canvas, 64, 20, "First Of All,\n...      >"); | ||||||
|  |     } else if(m->page == 2) { | ||||||
|  |         canvas_draw_icon(canvas, 0, height - 48, &I_DolphinFirstStart2_59x51); | ||||||
|  |         elements_multiline_text_framed(canvas, 64, 20, "Thank you\nfor your\nsupport! >"); | ||||||
|  |     } else if(m->page == 3) { | ||||||
|  |         canvas_draw_icon(canvas, width - 57, height - 48, &I_DolphinFirstStart3_57x48); | ||||||
|  |         elements_multiline_text_framed(canvas, 0, 20, "Kickstarter\ncampaign\nwas INSANE! >"); | ||||||
|  |     } else if(m->page == 4) { | ||||||
|  |         canvas_draw_icon(canvas, width - 67, height - 50, &I_DolphinFirstStart4_67x53); | ||||||
|  |         elements_multiline_text_framed(canvas, 0, 17, "Now\nallow me\nto introduce\nmyself >"); | ||||||
|  |     } else if(m->page == 5) { | ||||||
|  |         char buf[64]; | ||||||
|  |         snprintf( | ||||||
|  |             buf, | ||||||
|  |             64, | ||||||
|  |             "%s %s%s", | ||||||
|  |             "I am", | ||||||
|  |             my_name ? my_name : "Unknown", | ||||||
|  |             ",\ncyberdesktop\nliving in your\npocket >"); | ||||||
|  |         canvas_draw_icon(canvas, 0, height - 48, &I_DolphinFirstStart5_54x49); | ||||||
|  |         elements_multiline_text_framed(canvas, 60, 17, buf); | ||||||
|  |     } else if(m->page == 6) { | ||||||
|  |         canvas_draw_icon(canvas, 0, height - 48, &I_DolphinFirstStart6_58x54); | ||||||
|  |         elements_multiline_text_framed( | ||||||
|  |             canvas, 63, 17, "I can grow\nsmart'n'cool\nif you use me\noften >"); | ||||||
|  |     } else if(m->page == 7) { | ||||||
|  |         canvas_draw_icon(canvas, width - 61, height - 48, &I_DolphinFirstStart7_61x51); | ||||||
|  |         elements_multiline_text_framed( | ||||||
|  |             canvas, 0, 17, "As long as\nyou read, write\nand emulate >"); | ||||||
|  |     } else if(m->page == 8) { | ||||||
|  |         canvas_draw_icon(canvas, width - 56, height - 48, &I_DolphinFirstStart8_56x51); | ||||||
|  |         elements_multiline_text_framed( | ||||||
|  |             canvas, 0, 17, "You can check\nmy level and\nmood in the\nPassport menu"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | View* desktop_first_start_get_view(DesktopFirstStartView* first_start_view) { | ||||||
|  |     furi_assert(first_start_view); | ||||||
|  |     return first_start_view->view; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool desktop_first_start_input(InputEvent* event, void* context) { | ||||||
|  |     furi_assert(event); | ||||||
|  |     DesktopFirstStartView* first_start_view = context; | ||||||
|  | 
 | ||||||
|  |     if(event->type == InputTypeShort) { | ||||||
|  |         DesktopFirstStartViewModel* model = view_get_model(first_start_view->view); | ||||||
|  |         if(event->key == InputKeyLeft) { | ||||||
|  |             if(model->page > 0) model->page--; | ||||||
|  |         } else if(event->key == InputKeyRight) { | ||||||
|  |             uint32_t page = ++model->page; | ||||||
|  |             if(page > 8) { | ||||||
|  |                 first_start_view->callback(DesktopFirstStartCompleted, first_start_view->context); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |         view_commit_model(first_start_view->view, true); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DesktopFirstStartView* desktop_first_start_alloc() { | ||||||
|  |     DesktopFirstStartView* first_start_view = furi_alloc(sizeof(DesktopFirstStartView)); | ||||||
|  |     first_start_view->view = view_alloc(); | ||||||
|  |     view_allocate_model( | ||||||
|  |         first_start_view->view, ViewModelTypeLocking, sizeof(DesktopFirstStartViewModel)); | ||||||
|  |     view_set_context(first_start_view->view, first_start_view); | ||||||
|  |     view_set_draw_callback(first_start_view->view, (ViewDrawCallback)desktop_first_start_render); | ||||||
|  |     view_set_input_callback(first_start_view->view, desktop_first_start_input); | ||||||
|  | 
 | ||||||
|  |     return first_start_view; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_first_start_free(DesktopFirstStartView* first_start_view) { | ||||||
|  |     furi_assert(first_start_view); | ||||||
|  | 
 | ||||||
|  |     view_free(first_start_view->view); | ||||||
|  |     free(first_start_view); | ||||||
|  | } | ||||||
							
								
								
									
										35
									
								
								applications/desktop/views/desktop_first_start.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								applications/desktop/views/desktop_first_start.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,35 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <gui/gui_i.h> | ||||||
|  | #include <gui/view.h> | ||||||
|  | #include <gui/canvas.h> | ||||||
|  | #include <gui/elements.h> | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     DesktopFirstStartCompleted, | ||||||
|  | } DesktopFirstStartEvent; | ||||||
|  | 
 | ||||||
|  | typedef struct DesktopFirstStartView DesktopFirstStartView; | ||||||
|  | 
 | ||||||
|  | typedef void (*DesktopFirstStartViewCallback)(DesktopFirstStartEvent event, void* context); | ||||||
|  | 
 | ||||||
|  | struct DesktopFirstStartView { | ||||||
|  |     View* view; | ||||||
|  |     DesktopFirstStartViewCallback callback; | ||||||
|  |     void* context; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t page; | ||||||
|  | } DesktopFirstStartViewModel; | ||||||
|  | 
 | ||||||
|  | void desktop_first_start_set_callback( | ||||||
|  |     DesktopFirstStartView* main_view, | ||||||
|  |     DesktopFirstStartViewCallback callback, | ||||||
|  |     void* context); | ||||||
|  | 
 | ||||||
|  | View* desktop_first_start_get_view(DesktopFirstStartView* main_view); | ||||||
|  | 
 | ||||||
|  | DesktopFirstStartView* desktop_first_start_alloc(); | ||||||
|  | void desktop_first_start_free(DesktopFirstStartView* main_view); | ||||||
							
								
								
									
										66
									
								
								applications/desktop/views/desktop_hw_mismatch.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								applications/desktop/views/desktop_hw_mismatch.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,66 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include "../desktop_i.h" | ||||||
|  | #include <furi-hal.h> | ||||||
|  | #include <furi-hal-version.h> | ||||||
|  | 
 | ||||||
|  | #include "desktop_hw_mismatch.h" | ||||||
|  | 
 | ||||||
|  | void desktop_hw_mismatch_set_callback( | ||||||
|  |     DesktopHwMismatchView* main_view, | ||||||
|  |     DesktopHwMismatchViewCallback callback, | ||||||
|  |     void* context) { | ||||||
|  |     furi_assert(main_view); | ||||||
|  |     furi_assert(callback); | ||||||
|  |     main_view->callback = callback; | ||||||
|  |     main_view->context = context; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_hw_mismatch_render(Canvas* canvas, void* model) { | ||||||
|  |     canvas_clear(canvas); | ||||||
|  |     canvas_set_color(canvas, ColorBlack); | ||||||
|  |     canvas_set_font(canvas, FontPrimary); | ||||||
|  |     canvas_draw_str(canvas, 2, 15, "!!!! HW Mismatch !!!!"); | ||||||
|  | 
 | ||||||
|  |     char buffer[64]; | ||||||
|  |     canvas_set_font(canvas, FontSecondary); | ||||||
|  |     snprintf(buffer, 64, "HW target: F%d", furi_hal_version_get_hw_target()); | ||||||
|  |     canvas_draw_str(canvas, 5, 27, buffer); | ||||||
|  |     canvas_draw_str(canvas, 5, 38, "FW target: " TARGET); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | View* desktop_hw_mismatch_get_view(DesktopHwMismatchView* hw_mismatch_view) { | ||||||
|  |     furi_assert(hw_mismatch_view); | ||||||
|  |     return hw_mismatch_view->view; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool desktop_hw_mismatch_input(InputEvent* event, void* context) { | ||||||
|  |     furi_assert(event); | ||||||
|  |     furi_assert(context); | ||||||
|  | 
 | ||||||
|  |     DesktopHwMismatchView* hw_mismatch_view = context; | ||||||
|  | 
 | ||||||
|  |     if(event->type == InputTypeShort) { | ||||||
|  |         hw_mismatch_view->callback(DesktopHwMismatchEventExit, hw_mismatch_view->context); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DesktopHwMismatchView* desktop_hw_mismatch_alloc() { | ||||||
|  |     DesktopHwMismatchView* hw_mismatch_view = furi_alloc(sizeof(DesktopHwMismatchView)); | ||||||
|  |     hw_mismatch_view->view = view_alloc(); | ||||||
|  |     view_allocate_model( | ||||||
|  |         hw_mismatch_view->view, ViewModelTypeLocking, sizeof(DesktopHwMismatchViewModel)); | ||||||
|  |     view_set_context(hw_mismatch_view->view, hw_mismatch_view); | ||||||
|  |     view_set_draw_callback(hw_mismatch_view->view, (ViewDrawCallback)desktop_hw_mismatch_render); | ||||||
|  |     view_set_input_callback(hw_mismatch_view->view, desktop_hw_mismatch_input); | ||||||
|  | 
 | ||||||
|  |     return hw_mismatch_view; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_hw_mismatch_free(DesktopHwMismatchView* hw_mismatch_view) { | ||||||
|  |     furi_assert(hw_mismatch_view); | ||||||
|  | 
 | ||||||
|  |     view_free(hw_mismatch_view->view); | ||||||
|  |     free(hw_mismatch_view); | ||||||
|  | } | ||||||
							
								
								
									
										38
									
								
								applications/desktop/views/desktop_hw_mismatch.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								applications/desktop/views/desktop_hw_mismatch.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,38 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <gui/gui_i.h> | ||||||
|  | #include <gui/view.h> | ||||||
|  | #include <gui/canvas.h> | ||||||
|  | #include <gui/elements.h> | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     DesktopHwMismatchEventExit, | ||||||
|  | } DesktopHwMismatchEvent; | ||||||
|  | 
 | ||||||
|  | typedef struct DesktopHwMismatchView DesktopHwMismatchView; | ||||||
|  | 
 | ||||||
|  | typedef void (*DesktopHwMismatchViewCallback)(DesktopHwMismatchEvent event, void* context); | ||||||
|  | 
 | ||||||
|  | struct DesktopHwMismatchView { | ||||||
|  |     View* view; | ||||||
|  |     DesktopHwMismatchViewCallback callback; | ||||||
|  |     void* context; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     IconAnimation* animation; | ||||||
|  |     uint8_t scene_num; | ||||||
|  |     uint8_t hint_timeout; | ||||||
|  |     bool locked; | ||||||
|  | } DesktopHwMismatchViewModel; | ||||||
|  | 
 | ||||||
|  | void desktop_hw_mismatch_set_callback( | ||||||
|  |     DesktopHwMismatchView* hw_mismatch_view, | ||||||
|  |     DesktopHwMismatchViewCallback callback, | ||||||
|  |     void* context); | ||||||
|  | 
 | ||||||
|  | View* desktop_hw_mismatch_get_view(DesktopHwMismatchView* hw_mismatch_view); | ||||||
|  | 
 | ||||||
|  | DesktopHwMismatchView* desktop_hw_mismatch_alloc(); | ||||||
|  | void desktop_hw_mismatch_free(DesktopHwMismatchView* hw_mismatch_view); | ||||||
							
								
								
									
										111
									
								
								applications/desktop/views/desktop_lock_menu.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								applications/desktop/views/desktop_lock_menu.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,111 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include "../desktop_i.h" | ||||||
|  | #include "desktop_lock_menu.h" | ||||||
|  | 
 | ||||||
|  | void desktop_lock_menu_set_callback( | ||||||
|  |     DesktopLockMenuView* lock_menu, | ||||||
|  |     DesktopLockMenuViewCallback callback, | ||||||
|  |     void* context) { | ||||||
|  |     furi_assert(lock_menu); | ||||||
|  |     furi_assert(callback); | ||||||
|  |     lock_menu->callback = callback; | ||||||
|  |     lock_menu->context = context; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_lock_menu_reset_idx(DesktopLockMenuView* lock_menu) { | ||||||
|  |     with_view_model( | ||||||
|  |         lock_menu->view, (DesktopLockMenuViewModel * model) { | ||||||
|  |             model->idx = 0; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | static void lock_menu_callback(void* context, uint8_t index) { | ||||||
|  |     furi_assert(context); | ||||||
|  |     DesktopLockMenuView* lock_menu = context; | ||||||
|  |     switch(index) { | ||||||
|  |     case 0: // lock
 | ||||||
|  |         lock_menu->callback(DesktopLockMenuEventLock, lock_menu->context); | ||||||
|  |     default: // wip message
 | ||||||
|  |         with_view_model( | ||||||
|  |             lock_menu->view, (DesktopLockMenuViewModel * model) { | ||||||
|  |                 model->hint_timeout = HINT_TIMEOUT_L; | ||||||
|  |                 return true; | ||||||
|  |             }); | ||||||
|  |         break; | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_lock_menu_render(Canvas* canvas, void* model) { | ||||||
|  |     const char* Lockmenu_Items[3] = {"Lock", "Set PIN", "DUMB mode"}; | ||||||
|  | 
 | ||||||
|  |     DesktopLockMenuViewModel* m = model; | ||||||
|  |     canvas_clear(canvas); | ||||||
|  |     canvas_set_color(canvas, ColorBlack); | ||||||
|  |     canvas_draw_icon(canvas, -57, 0, &I_DoorLeft_70x55); | ||||||
|  |     canvas_draw_icon(canvas, 115, 0, &I_DoorRight_70x55); | ||||||
|  |     canvas_set_font(canvas, FontSecondary); | ||||||
|  | 
 | ||||||
|  |     for(uint8_t i = 0; i < 3; ++i) { | ||||||
|  |         canvas_draw_str_aligned( | ||||||
|  |             canvas, | ||||||
|  |             64, | ||||||
|  |             13 + (i * 17), | ||||||
|  |             AlignCenter, | ||||||
|  |             AlignCenter, | ||||||
|  |             (m->hint_timeout && m->idx == i && m->idx) ? "Not implemented" : Lockmenu_Items[i]); | ||||||
|  |         if(m->idx == i) elements_frame(canvas, 15, 5 + (i * 17), 98, 15); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | View* desktop_lock_menu_get_view(DesktopLockMenuView* lock_menu) { | ||||||
|  |     furi_assert(lock_menu); | ||||||
|  |     return lock_menu->view; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool desktop_lock_menu_input(InputEvent* event, void* context) { | ||||||
|  |     furi_assert(event); | ||||||
|  |     furi_assert(context); | ||||||
|  | 
 | ||||||
|  |     DesktopLockMenuView* lock_menu = context; | ||||||
|  |     uint8_t idx; | ||||||
|  | 
 | ||||||
|  |     if(event->type != InputTypeShort) return false; | ||||||
|  |     with_view_model( | ||||||
|  |         lock_menu->view, (DesktopLockMenuViewModel * model) { | ||||||
|  |             model->hint_timeout = 0; // clear hint timeout
 | ||||||
|  |             if(event->key == InputKeyUp) { | ||||||
|  |                 model->idx = CLAMP(model->idx - 1, 2, 0); | ||||||
|  |             } else if(event->key == InputKeyDown) { | ||||||
|  |                 model->idx = CLAMP(model->idx + 1, 2, 0); | ||||||
|  |             } | ||||||
|  |             idx = model->idx; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     if(event->key == InputKeyBack) { | ||||||
|  |         lock_menu->callback(DesktopLockMenuEventExit, lock_menu->context); | ||||||
|  |     } else if(event->key == InputKeyOk) { | ||||||
|  |         lock_menu_callback(lock_menu, idx); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DesktopLockMenuView* desktop_lock_menu_alloc() { | ||||||
|  |     DesktopLockMenuView* lock_menu = furi_alloc(sizeof(DesktopLockMenuView)); | ||||||
|  |     lock_menu->view = view_alloc(); | ||||||
|  |     view_allocate_model(lock_menu->view, ViewModelTypeLocking, sizeof(DesktopLockMenuViewModel)); | ||||||
|  |     view_set_context(lock_menu->view, lock_menu); | ||||||
|  |     view_set_draw_callback(lock_menu->view, (ViewDrawCallback)desktop_lock_menu_render); | ||||||
|  |     view_set_input_callback(lock_menu->view, desktop_lock_menu_input); | ||||||
|  | 
 | ||||||
|  |     return lock_menu; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_lock_menu_free(DesktopLockMenuView* lock_menu_view) { | ||||||
|  |     furi_assert(lock_menu_view); | ||||||
|  | 
 | ||||||
|  |     view_free(lock_menu_view->view); | ||||||
|  |     free(lock_menu_view); | ||||||
|  | } | ||||||
							
								
								
									
										39
									
								
								applications/desktop/views/desktop_lock_menu.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								applications/desktop/views/desktop_lock_menu.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,39 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <gui/gui_i.h> | ||||||
|  | #include <gui/view.h> | ||||||
|  | #include <gui/canvas.h> | ||||||
|  | #include <gui/elements.h> | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     DesktopLockMenuEventLock, | ||||||
|  |     DesktopLockMenuEventUnlock, | ||||||
|  |     DesktopLockMenuEventExit, | ||||||
|  | } DesktopLockMenuEvent; | ||||||
|  | 
 | ||||||
|  | typedef struct DesktopLockMenuView DesktopLockMenuView; | ||||||
|  | 
 | ||||||
|  | typedef void (*DesktopLockMenuViewCallback)(DesktopLockMenuEvent event, void* context); | ||||||
|  | 
 | ||||||
|  | struct DesktopLockMenuView { | ||||||
|  |     View* view; | ||||||
|  |     DesktopLockMenuViewCallback callback; | ||||||
|  |     void* context; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     uint8_t idx; | ||||||
|  |     uint8_t hint_timeout; | ||||||
|  |     bool locked; | ||||||
|  | } DesktopLockMenuViewModel; | ||||||
|  | 
 | ||||||
|  | void desktop_lock_menu_set_callback( | ||||||
|  |     DesktopLockMenuView* lock_menu, | ||||||
|  |     DesktopLockMenuViewCallback callback, | ||||||
|  |     void* context); | ||||||
|  | 
 | ||||||
|  | View* desktop_lock_menu_get_view(DesktopLockMenuView* lock_menu); | ||||||
|  | void desktop_lock_menu_reset_idx(DesktopLockMenuView* lock_menu); | ||||||
|  | DesktopLockMenuView* desktop_lock_menu_alloc(); | ||||||
|  | void desktop_lock_menu_free(DesktopLockMenuView* lock_menu); | ||||||
							
								
								
									
										171
									
								
								applications/desktop/views/desktop_locked.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								applications/desktop/views/desktop_locked.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,171 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include "../desktop_i.h" | ||||||
|  | #include "desktop_locked.h" | ||||||
|  | 
 | ||||||
|  | static const Icon* idle_scenes[] = {&A_Wink_128x64, &A_WatchingTV_128x64}; | ||||||
|  | 
 | ||||||
|  | void desktop_locked_set_callback( | ||||||
|  |     DesktopLockedView* locked_view, | ||||||
|  |     DesktopLockedViewCallback callback, | ||||||
|  |     void* context) { | ||||||
|  |     furi_assert(locked_view); | ||||||
|  |     furi_assert(callback); | ||||||
|  |     locked_view->callback = callback; | ||||||
|  |     locked_view->context = context; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void locked_view_timer_callback(void* context) { | ||||||
|  |     DesktopLockedView* locked_view = context; | ||||||
|  |     locked_view->callback(DesktopLockedEventUpdate, locked_view->context); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // temporary locked screen animation managment
 | ||||||
|  | static void | ||||||
|  |     desktop_scene_handler_set_scene(DesktopLockedView* locked_view, const Icon* icon_data) { | ||||||
|  |     with_view_model( | ||||||
|  |         locked_view->view, (DesktopLockedViewModel * model) { | ||||||
|  |             if(model->animation) icon_animation_free(model->animation); | ||||||
|  |             model->animation = icon_animation_alloc(icon_data); | ||||||
|  |             icon_animation_start(model->animation); | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_locked_update_hint_timeout(DesktopLockedView* locked_view) { | ||||||
|  |     with_view_model( | ||||||
|  |         locked_view->view, (DesktopLockedViewModel * model) { | ||||||
|  |             model->hint_timeout = HINT_TIMEOUT_H; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_locked_reset_door_pos(DesktopLockedView* locked_view) { | ||||||
|  |     with_view_model( | ||||||
|  |         locked_view->view, (DesktopLockedViewModel * model) { | ||||||
|  |             model->animation_seq_end = false; | ||||||
|  |             model->door_left_x = -57; | ||||||
|  |             model->door_right_x = 115; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_locked_manage_redraw(DesktopLockedView* locked_view) { | ||||||
|  |     bool animation_seq_end; | ||||||
|  | 
 | ||||||
|  |     with_view_model( | ||||||
|  |         locked_view->view, (DesktopLockedViewModel * model) { | ||||||
|  |             model->animation_seq_end = !model->door_left_x; | ||||||
|  |             animation_seq_end = model->animation_seq_end; | ||||||
|  | 
 | ||||||
|  |             if(!model->animation_seq_end) { | ||||||
|  |                 model->door_left_x = CLAMP(model->door_left_x + 5, 0, -57); | ||||||
|  |                 model->door_right_x = CLAMP(model->door_right_x - 5, 115, 60); | ||||||
|  |             } | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | 
 | ||||||
|  |     if(animation_seq_end) { | ||||||
|  |         osTimerStop(locked_view->timer); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_locked_reset_counter(DesktopLockedView* locked_view) { | ||||||
|  |     locked_view->lock_count = 0; | ||||||
|  |     locked_view->lock_lastpress = 0; | ||||||
|  | 
 | ||||||
|  |     with_view_model( | ||||||
|  |         locked_view->view, (DesktopLockedViewModel * model) { | ||||||
|  |             model->hint_timeout = 0; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_locked_render(Canvas* canvas, void* model) { | ||||||
|  |     DesktopLockedViewModel* m = model; | ||||||
|  | 
 | ||||||
|  |     canvas_clear(canvas); | ||||||
|  |     canvas_set_color(canvas, ColorBlack); | ||||||
|  | 
 | ||||||
|  |     if(!m->animation_seq_end) { | ||||||
|  |         canvas_draw_icon(canvas, m->door_left_x, 0, &I_DoorLeft_70x55); | ||||||
|  |         canvas_draw_icon(canvas, m->door_right_x, 0, &I_DoorRight_70x55); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(m->animation && m->animation_seq_end) { | ||||||
|  |         canvas_draw_icon_animation(canvas, 0, -3, m->animation); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(m->hint_timeout) { | ||||||
|  |         m->hint_timeout--; | ||||||
|  | 
 | ||||||
|  |         if(!m->animation_seq_end) { | ||||||
|  |             canvas_set_font(canvas, FontPrimary); | ||||||
|  |             elements_multiline_text_framed(canvas, 42, 30, "Locked"); | ||||||
|  |         } else { | ||||||
|  |             canvas_set_font(canvas, FontSecondary); | ||||||
|  |             canvas_draw_icon(canvas, 13, 5, &I_LockPopup_100x49); | ||||||
|  |             elements_multiline_text(canvas, 65, 20, "To unlock\npress:"); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | View* desktop_locked_get_view(DesktopLockedView* locked_view) { | ||||||
|  |     furi_assert(locked_view); | ||||||
|  |     return locked_view->view; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool desktop_locked_input(InputEvent* event, void* context) { | ||||||
|  |     furi_assert(event); | ||||||
|  |     furi_assert(context); | ||||||
|  | 
 | ||||||
|  |     DesktopLockedView* locked_view = context; | ||||||
|  |     if(event->type == InputTypeShort) { | ||||||
|  |         with_view_model( | ||||||
|  |             locked_view->view, (DesktopLockedViewModel * model) { | ||||||
|  |                 model->hint_timeout = HINT_TIMEOUT_L; | ||||||
|  |                 return true; | ||||||
|  |             }); | ||||||
|  | 
 | ||||||
|  |         if(event->key == InputKeyBack) { | ||||||
|  |             uint32_t press_time = HAL_GetTick(); | ||||||
|  | 
 | ||||||
|  |             // check if pressed sequentially
 | ||||||
|  |             if(press_time - locked_view->lock_lastpress > UNLOCK_RST_TIMEOUT) { | ||||||
|  |                 locked_view->lock_lastpress = press_time; | ||||||
|  |                 locked_view->lock_count = 0; | ||||||
|  |             } else if(press_time - locked_view->lock_lastpress < UNLOCK_RST_TIMEOUT) { | ||||||
|  |                 locked_view->lock_lastpress = press_time; | ||||||
|  |                 locked_view->lock_count++; | ||||||
|  |             } | ||||||
|  | 
 | ||||||
|  |             if(locked_view->lock_count == UNLOCK_CNT) { | ||||||
|  |                 locked_view->lock_count = 0; | ||||||
|  |                 locked_view->callback(DesktopLockedEventUnlock, locked_view->context); | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |     // All events consumed
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DesktopLockedView* desktop_locked_alloc() { | ||||||
|  |     DesktopLockedView* locked_view = furi_alloc(sizeof(DesktopLockedView)); | ||||||
|  |     locked_view->view = view_alloc(); | ||||||
|  |     locked_view->timer = | ||||||
|  |         osTimerNew(locked_view_timer_callback, osTimerPeriodic, locked_view, NULL); | ||||||
|  | 
 | ||||||
|  |     view_allocate_model(locked_view->view, ViewModelTypeLocking, sizeof(DesktopLockedViewModel)); | ||||||
|  |     view_set_context(locked_view->view, locked_view); | ||||||
|  |     view_set_draw_callback(locked_view->view, (ViewDrawCallback)desktop_locked_render); | ||||||
|  |     view_set_input_callback(locked_view->view, desktop_locked_input); | ||||||
|  | 
 | ||||||
|  |     desktop_scene_handler_set_scene(locked_view, idle_scenes[random() % COUNT_OF(idle_scenes)]); | ||||||
|  |     return locked_view; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_locked_free(DesktopLockedView* locked_view) { | ||||||
|  |     furi_assert(locked_view); | ||||||
|  |     osTimerDelete(locked_view->timer); | ||||||
|  |     view_free(locked_view->view); | ||||||
|  |     free(locked_view); | ||||||
|  | } | ||||||
							
								
								
									
										55
									
								
								applications/desktop/views/desktop_locked.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								applications/desktop/views/desktop_locked.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,55 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <gui/gui_i.h> | ||||||
|  | #include <gui/view.h> | ||||||
|  | #include <gui/canvas.h> | ||||||
|  | #include <gui/elements.h> | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | #define UNLOCK_RST_TIMEOUT 200 | ||||||
|  | #define UNLOCK_CNT 2 // 3 actually
 | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     DesktopLockedEventUnlock, | ||||||
|  |     DesktopLockedEventUpdate, | ||||||
|  | } DesktopLockedEvent; | ||||||
|  | 
 | ||||||
|  | typedef struct DesktopLockedView DesktopLockedView; | ||||||
|  | 
 | ||||||
|  | typedef void (*DesktopLockedViewCallback)(DesktopLockedEvent event, void* context); | ||||||
|  | 
 | ||||||
|  | struct DesktopLockedView { | ||||||
|  |     View* view; | ||||||
|  |     DesktopLockedViewCallback callback; | ||||||
|  |     void* context; | ||||||
|  | 
 | ||||||
|  |     osTimerId_t timer; | ||||||
|  |     uint8_t lock_count; | ||||||
|  |     uint32_t lock_lastpress; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     IconAnimation* animation; | ||||||
|  |     uint8_t scene_num; | ||||||
|  |     int8_t door_left_x; | ||||||
|  |     int8_t door_right_x; | ||||||
|  |     uint8_t hint_timeout; | ||||||
|  |     bool animation_seq_end; | ||||||
|  | 
 | ||||||
|  | } DesktopLockedViewModel; | ||||||
|  | 
 | ||||||
|  | void desktop_locked_set_callback( | ||||||
|  |     DesktopLockedView* locked_view, | ||||||
|  |     DesktopLockedViewCallback callback, | ||||||
|  |     void* context); | ||||||
|  | 
 | ||||||
|  | void desktop_locked_update_hint_timeout(DesktopLockedView* locked_view); | ||||||
|  | void desktop_locked_reset_counter(DesktopLockedView* locked_view); | ||||||
|  | void desktop_locked_reset_door_pos(DesktopLockedView* locked_view); | ||||||
|  | void desktop_locked_manage_redraw(DesktopLockedView* locked_view); | ||||||
|  | 
 | ||||||
|  | View* desktop_locked_get_view(DesktopLockedView* locked_view); | ||||||
|  | DesktopLockedView* desktop_locked_alloc(); | ||||||
|  | void desktop_locked_free(DesktopLockedView* locked_view); | ||||||
|  | void desktop_main_unlocked(DesktopMainView* main_view); | ||||||
|  | void desktop_main_reset_hint(DesktopMainView* main_view); | ||||||
							
								
								
									
										116
									
								
								applications/desktop/views/desktop_main.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								applications/desktop/views/desktop_main.c
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,116 @@ | |||||||
|  | #include <furi.h> | ||||||
|  | #include "../desktop_i.h" | ||||||
|  | #include "desktop_main.h" | ||||||
|  | 
 | ||||||
|  | static const Icon* idle_scenes[] = {&A_Wink_128x64, &A_WatchingTV_128x64}; | ||||||
|  | 
 | ||||||
|  | void desktop_main_set_callback( | ||||||
|  |     DesktopMainView* main_view, | ||||||
|  |     DesktopMainViewCallback callback, | ||||||
|  |     void* context) { | ||||||
|  |     furi_assert(main_view); | ||||||
|  |     furi_assert(callback); | ||||||
|  |     main_view->callback = callback; | ||||||
|  |     main_view->context = context; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_main_reset_hint(DesktopMainView* main_view) { | ||||||
|  |     with_view_model( | ||||||
|  |         main_view->view, (DesktopMainViewModel * model) { | ||||||
|  |             model->hint_timeout = 0; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | // temporary main screen animation managment
 | ||||||
|  | void desktop_scene_handler_set_scene(DesktopMainView* main_view, const Icon* icon_data) { | ||||||
|  |     with_view_model( | ||||||
|  |         main_view->view, (DesktopMainViewModel * model) { | ||||||
|  |             if(model->animation) icon_animation_free(model->animation); | ||||||
|  |             model->animation = icon_animation_alloc(icon_data); | ||||||
|  |             icon_animation_start(model->animation); | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_scene_handler_switch_scene(DesktopMainView* main_view) { | ||||||
|  |     with_view_model( | ||||||
|  |         main_view->view, (DesktopMainViewModel * model) { | ||||||
|  |             if(icon_animation_is_last_frame(model->animation)) { | ||||||
|  |                 if(model->animation) icon_animation_free(model->animation); | ||||||
|  |                 model->animation = icon_animation_alloc(idle_scenes[model->scene_num]); | ||||||
|  |                 icon_animation_start(model->animation); | ||||||
|  |                 model->scene_num = random() % COUNT_OF(idle_scenes); | ||||||
|  |             } | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_main_render(Canvas* canvas, void* model) { | ||||||
|  |     canvas_clear(canvas); | ||||||
|  |     DesktopMainViewModel* m = model; | ||||||
|  | 
 | ||||||
|  |     if(m->animation) { | ||||||
|  |         canvas_draw_icon_animation(canvas, 0, -3, m->animation); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     if(m->unlocked && m->hint_timeout) { | ||||||
|  |         m->hint_timeout = CLAMP(m->hint_timeout - 1, 2, 0); | ||||||
|  |         canvas_set_font(canvas, FontPrimary); | ||||||
|  |         elements_multiline_text_framed(canvas, 42, 30, "Unlocked"); | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | View* desktop_main_get_view(DesktopMainView* main_view) { | ||||||
|  |     furi_assert(main_view); | ||||||
|  |     return main_view->view; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | bool desktop_main_input(InputEvent* event, void* context) { | ||||||
|  |     furi_assert(event); | ||||||
|  |     furi_assert(context); | ||||||
|  | 
 | ||||||
|  |     DesktopMainView* main_view = context; | ||||||
|  | 
 | ||||||
|  |     if(event->key == InputKeyOk && event->type == InputTypeShort) { | ||||||
|  |         main_view->callback(DesktopMainEventOpenMenu, main_view->context); | ||||||
|  |     } else if(event->key == InputKeyDown && event->type == InputTypeLong) { | ||||||
|  |         main_view->callback(DesktopMainEventOpenDebug, main_view->context); | ||||||
|  |     } else if(event->key == InputKeyUp && event->type == InputTypeShort) { | ||||||
|  |         main_view->callback(DesktopMainEventOpenLockMenu, main_view->context); | ||||||
|  |     } else if(event->key == InputKeyDown && event->type == InputTypeShort) { | ||||||
|  |         main_view->callback(DesktopMainEventOpenArchive, main_view->context); | ||||||
|  |     } else if(event->key == InputKeyLeft && event->type == InputTypeShort) { | ||||||
|  |         main_view->callback(DesktopMainEventOpenFavorite, main_view->context); | ||||||
|  |     } | ||||||
|  |     desktop_main_reset_hint(main_view); | ||||||
|  | 
 | ||||||
|  |     return true; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | DesktopMainView* desktop_main_alloc() { | ||||||
|  |     DesktopMainView* main_view = furi_alloc(sizeof(DesktopMainView)); | ||||||
|  |     main_view->view = view_alloc(); | ||||||
|  |     view_allocate_model(main_view->view, ViewModelTypeLocking, sizeof(DesktopMainViewModel)); | ||||||
|  |     view_set_context(main_view->view, main_view); | ||||||
|  |     view_set_draw_callback(main_view->view, (ViewDrawCallback)desktop_main_render); | ||||||
|  |     view_set_input_callback(main_view->view, desktop_main_input); | ||||||
|  | 
 | ||||||
|  |     desktop_scene_handler_set_scene(main_view, idle_scenes[random() % COUNT_OF(idle_scenes)]); | ||||||
|  | 
 | ||||||
|  |     return main_view; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_main_free(DesktopMainView* main_view) { | ||||||
|  |     furi_assert(main_view); | ||||||
|  |     view_free(main_view->view); | ||||||
|  |     free(main_view); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void desktop_main_unlocked(DesktopMainView* main_view) { | ||||||
|  |     with_view_model( | ||||||
|  |         main_view->view, (DesktopMainViewModel * model) { | ||||||
|  |             model->unlocked = true; | ||||||
|  |             model->hint_timeout = 2; | ||||||
|  |             return true; | ||||||
|  |         }); | ||||||
|  | } | ||||||
							
								
								
									
										43
									
								
								applications/desktop/views/desktop_main.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								applications/desktop/views/desktop_main.h
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,43 @@ | |||||||
|  | #pragma once | ||||||
|  | 
 | ||||||
|  | #include <gui/gui_i.h> | ||||||
|  | #include <gui/view.h> | ||||||
|  | #include <gui/canvas.h> | ||||||
|  | #include <gui/elements.h> | ||||||
|  | #include <furi.h> | ||||||
|  | 
 | ||||||
|  | typedef enum { | ||||||
|  |     DesktopMainEventOpenMenu, | ||||||
|  |     DesktopMainEventOpenLockMenu, | ||||||
|  |     DesktopMainEventOpenDebug, | ||||||
|  |     DesktopMainEventUnlocked, | ||||||
|  |     DesktopMainEventOpenArchive, | ||||||
|  |     DesktopMainEventOpenFavorite, | ||||||
|  | } DesktopMainEvent; | ||||||
|  | 
 | ||||||
|  | typedef struct DesktopMainView DesktopMainView; | ||||||
|  | 
 | ||||||
|  | typedef void (*DesktopMainViewCallback)(DesktopMainEvent event, void* context); | ||||||
|  | 
 | ||||||
|  | struct DesktopMainView { | ||||||
|  |     View* view; | ||||||
|  |     DesktopMainViewCallback callback; | ||||||
|  |     void* context; | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | typedef struct { | ||||||
|  |     IconAnimation* animation; | ||||||
|  |     uint8_t scene_num; | ||||||
|  |     uint8_t hint_timeout; | ||||||
|  |     bool unlocked; | ||||||
|  | } DesktopMainViewModel; | ||||||
|  | 
 | ||||||
|  | void desktop_main_set_callback( | ||||||
|  |     DesktopMainView* main_view, | ||||||
|  |     DesktopMainViewCallback callback, | ||||||
|  |     void* context); | ||||||
|  | 
 | ||||||
|  | View* desktop_main_get_view(DesktopMainView* main_view); | ||||||
|  | 
 | ||||||
|  | DesktopMainView* desktop_main_alloc(); | ||||||
|  | void desktop_main_free(DesktopMainView* main_view); | ||||||
| @ -1,389 +1,9 @@ | |||||||
| #include "dolphin_i.h" | #include "dolphin_i.h" | ||||||
| #include <stdlib.h> | #include <furi.h> | ||||||
| #include "applications.h" |  | ||||||
| 
 | 
 | ||||||
| const Icon* idle_scenes[] = {&A_Wink_128x64, &A_WatchingTV_128x64}; | bool dolphin_load(Dolphin* dolphin) { | ||||||
| 
 |  | ||||||
| static void dolphin_switch_to_app(Dolphin* dolphin, const FlipperApplication* flipper_app) { |  | ||||||
|     furi_assert(dolphin); |     furi_assert(dolphin); | ||||||
|     furi_assert(flipper_app); |     return dolphin_state_load(dolphin->state); | ||||||
|     furi_assert(flipper_app->app); |  | ||||||
|     furi_assert(flipper_app->name); |  | ||||||
| 
 |  | ||||||
|     if(furi_thread_get_state(dolphin->scene_thread) != FuriThreadStateStopped) { |  | ||||||
|         FURI_LOG_E("Dolphin", "Thread is already running"); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     furi_thread_set_name(dolphin->scene_thread, flipper_app->name); |  | ||||||
|     furi_thread_set_stack_size(dolphin->scene_thread, flipper_app->stack_size); |  | ||||||
|     furi_thread_set_callback(dolphin->scene_thread, flipper_app->app); |  | ||||||
| 
 |  | ||||||
|     furi_thread_start(dolphin->scene_thread); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // temporary main screen animation managment
 |  | ||||||
| void dolphin_scene_handler_set_scene(Dolphin* dolphin, const Icon* icon_data) { |  | ||||||
|     with_view_model( |  | ||||||
|         dolphin->idle_view_main, (DolphinViewMainModel * model) { |  | ||||||
|             if(model->animation) icon_animation_free(model->animation); |  | ||||||
|             model->animation = icon_animation_alloc(icon_data); |  | ||||||
|             icon_animation_start(model->animation); |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void dolphin_scene_handler_switch_scene(Dolphin* dolphin) { |  | ||||||
|     with_view_model( |  | ||||||
|         dolphin->idle_view_main, (DolphinViewMainModel * model) { |  | ||||||
|             if(icon_animation_is_last_frame(model->animation)) { |  | ||||||
|                 if(model->animation) icon_animation_free(model->animation); |  | ||||||
|                 model->animation = icon_animation_alloc(idle_scenes[model->scene_num]); |  | ||||||
|                 icon_animation_start(model->animation); |  | ||||||
|                 model->scene_num = random() % COUNT_OF(idle_scenes); |  | ||||||
|             } |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool dolphin_view_first_start_input(InputEvent* event, void* context) { |  | ||||||
|     furi_assert(event); |  | ||||||
|     furi_assert(context); |  | ||||||
|     Dolphin* dolphin = context; |  | ||||||
|     if(event->type == InputTypeShort) { |  | ||||||
|         DolphinViewFirstStartModel* model = view_get_model(dolphin->idle_view_first_start); |  | ||||||
|         if(event->key == InputKeyLeft) { |  | ||||||
|             if(model->page > 0) model->page--; |  | ||||||
|         } else if(event->key == InputKeyRight) { |  | ||||||
|             uint32_t page = ++model->page; |  | ||||||
|             if(page > 8) { |  | ||||||
|                 dolphin_save(dolphin); |  | ||||||
|                 view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|         view_commit_model(dolphin->idle_view_first_start, true); |  | ||||||
|     } |  | ||||||
|     // All evennts cosumed
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void dolphin_lock_handler(InputEvent* event, Dolphin* dolphin) { |  | ||||||
|     furi_assert(event); |  | ||||||
|     furi_assert(dolphin); |  | ||||||
| 
 |  | ||||||
|     with_view_model( |  | ||||||
|         dolphin->idle_view_main, (DolphinViewMainModel * model) { |  | ||||||
|             model->hint_timeout = HINT_TIMEOUT_L; |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|     if(event->key == InputKeyBack && event->type == InputTypeShort) { |  | ||||||
|         uint32_t press_time = HAL_GetTick(); |  | ||||||
| 
 |  | ||||||
|         // check if pressed sequentially
 |  | ||||||
|         if(press_time - dolphin->lock_lastpress > UNLOCK_RST_TIMEOUT) { |  | ||||||
|             dolphin->lock_lastpress = press_time; |  | ||||||
|             dolphin->lock_count = 0; |  | ||||||
|         } else if(press_time - dolphin->lock_lastpress < UNLOCK_RST_TIMEOUT) { |  | ||||||
|             dolphin->lock_lastpress = press_time; |  | ||||||
|             dolphin->lock_count++; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(dolphin->lock_count == 2) { |  | ||||||
|             dolphin->locked = false; |  | ||||||
|             dolphin->lock_count = 0; |  | ||||||
| 
 |  | ||||||
|             with_view_model( |  | ||||||
|                 dolphin->view_lockmenu, (DolphinViewLockMenuModel * model) { |  | ||||||
|                     model->locked = false; |  | ||||||
|                     model->door_left_x = -57; // move doors to default pos
 |  | ||||||
|                     model->door_right_x = 115; |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
| 
 |  | ||||||
|             with_view_model( |  | ||||||
|                 dolphin->idle_view_main, (DolphinViewMainModel * model) { |  | ||||||
|                     model->hint_timeout = HINT_TIMEOUT_L; // "unlocked" hint timeout
 |  | ||||||
|                     model->locked = false; |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
| 
 |  | ||||||
|             view_port_enabled_set(dolphin->lock_viewport, false); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool dolphin_view_idle_main_input(InputEvent* event, void* context) { |  | ||||||
|     furi_assert(event); |  | ||||||
|     furi_assert(context); |  | ||||||
|     Dolphin* dolphin = context; |  | ||||||
|     // unlocked
 |  | ||||||
|     if(!dolphin->locked) { |  | ||||||
|         if(event->key == InputKeyOk && event->type == InputTypeShort) { |  | ||||||
|             with_value_mutex( |  | ||||||
|                 dolphin->menu_vm, (Menu * menu) { menu_ok(menu); }); |  | ||||||
|         } else if(event->key == InputKeyUp && event->type == InputTypeShort) { |  | ||||||
|             osTimerStart(dolphin->timeout_timer, 64); |  | ||||||
|             view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewLockMenu); |  | ||||||
|         } else if(event->key == InputKeyDown && event->type == InputTypeShort) { |  | ||||||
|             dolphin_switch_to_app(dolphin, &FLIPPER_ARCHIVE); |  | ||||||
|         } else if(event->key == InputKeyDown && event->type == InputTypeLong) { |  | ||||||
|             view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewStats); |  | ||||||
|         } else if(event->key == InputKeyBack && event->type == InputTypeShort) { |  | ||||||
|             view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         with_view_model( |  | ||||||
|             dolphin->idle_view_main, (DolphinViewMainModel * model) { |  | ||||||
|                 model->hint_timeout = 0; // clear hint timeout
 |  | ||||||
|                 return true; |  | ||||||
|             }); |  | ||||||
| 
 |  | ||||||
|     } else { |  | ||||||
|         // locked
 |  | ||||||
| 
 |  | ||||||
|         dolphin_lock_handler(event, dolphin); |  | ||||||
|         dolphin_scene_handler_switch_scene(dolphin); |  | ||||||
|     } |  | ||||||
|     // All events consumed
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void lock_menu_refresh_handler(void* p) { |  | ||||||
|     osMessageQueueId_t event_queue = p; |  | ||||||
|     DolphinEvent event; |  | ||||||
|     event.type = DolphinEventTypeTick; |  | ||||||
|     // Some tick events may lost and we don't care.
 |  | ||||||
|     osMessageQueuePut(event_queue, &event, 0, 0); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void lock_menu_callback(void* context, uint8_t index) { |  | ||||||
|     furi_assert(context); |  | ||||||
|     Dolphin* dolphin = context; |  | ||||||
|     switch(index) { |  | ||||||
|     // lock
 |  | ||||||
|     case 0: |  | ||||||
|         dolphin->locked = true; |  | ||||||
| 
 |  | ||||||
|         with_view_model( |  | ||||||
|             dolphin->view_lockmenu, (DolphinViewLockMenuModel * model) { |  | ||||||
|                 model->locked = true; |  | ||||||
|                 model->exit_timeout = HINT_TIMEOUT_H; |  | ||||||
|                 return true; |  | ||||||
|             }); |  | ||||||
| 
 |  | ||||||
|         with_view_model( |  | ||||||
|             dolphin->idle_view_main, (DolphinViewMainModel * model) { |  | ||||||
|                 model->locked = true; |  | ||||||
|                 return true; |  | ||||||
|             }); |  | ||||||
|         break; |  | ||||||
| 
 |  | ||||||
|     default: |  | ||||||
|         // wip message
 |  | ||||||
|         with_view_model( |  | ||||||
|             dolphin->view_lockmenu, (DolphinViewLockMenuModel * model) { |  | ||||||
|                 model->hint_timeout = HINT_TIMEOUT_H; |  | ||||||
|                 return true; |  | ||||||
|             }); |  | ||||||
|         break; |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| static void lock_icon_callback(Canvas* canvas, void* context) { |  | ||||||
|     furi_assert(context); |  | ||||||
|     Dolphin* dolphin = context; |  | ||||||
|     canvas_draw_icon_animation(canvas, 0, 0, dolphin->lock_icon); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool dolphin_view_lockmenu_input(InputEvent* event, void* context) { |  | ||||||
|     furi_assert(event); |  | ||||||
|     furi_assert(context); |  | ||||||
|     Dolphin* dolphin = context; |  | ||||||
| 
 |  | ||||||
|     if(event->type != InputTypeShort) return false; |  | ||||||
| 
 |  | ||||||
|     DolphinViewLockMenuModel* model = view_get_model(dolphin->view_lockmenu); |  | ||||||
| 
 |  | ||||||
|     model->hint_timeout = 0; // clear hint timeout
 |  | ||||||
| 
 |  | ||||||
|     if(event->key == InputKeyUp) { |  | ||||||
|         model->idx = CLAMP(model->idx - 1, 2, 0); |  | ||||||
|     } else if(event->key == InputKeyDown) { |  | ||||||
|         model->idx = CLAMP(model->idx + 1, 2, 0); |  | ||||||
|     } else if(event->key == InputKeyOk) { |  | ||||||
|         lock_menu_callback(context, model->idx); |  | ||||||
|     } else if(event->key == InputKeyBack) { |  | ||||||
|         model->idx = 0; |  | ||||||
|         view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); |  | ||||||
| 
 |  | ||||||
|         if(random() % 100 > 50) |  | ||||||
|             dolphin_scene_handler_set_scene( |  | ||||||
|                 dolphin, idle_scenes[random() % COUNT_OF(idle_scenes)]); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     view_commit_model(dolphin->view_lockmenu, true); |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| bool dolphin_view_idle_down_input(InputEvent* event, void* context) { |  | ||||||
|     furi_assert(event); |  | ||||||
|     furi_assert(context); |  | ||||||
|     Dolphin* dolphin = context; |  | ||||||
|     DolphinViewStatsScreens current; |  | ||||||
| 
 |  | ||||||
|     if(event->type != InputTypeShort) return false; |  | ||||||
| 
 |  | ||||||
|     DolphinViewStatsModel* model = view_get_model(dolphin->idle_view_dolphin_stats); |  | ||||||
| 
 |  | ||||||
|     current = model->screen; |  | ||||||
| 
 |  | ||||||
|     if(event->key == InputKeyDown) { |  | ||||||
|         model->screen = (model->screen + 1) % DolphinViewStatsTotalCount; |  | ||||||
|     } else if(event->key == InputKeyUp) { |  | ||||||
|         model->screen = |  | ||||||
|             ((model->screen - 1) + DolphinViewStatsTotalCount) % DolphinViewStatsTotalCount; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     view_commit_model(dolphin->idle_view_dolphin_stats, true); |  | ||||||
| 
 |  | ||||||
|     if(current == DolphinViewStatsMeta) { |  | ||||||
|         if(event->key == InputKeyLeft) { |  | ||||||
|             dolphin_deed(dolphin, DolphinDeedWrong); |  | ||||||
|         } else if(event->key == InputKeyRight) { |  | ||||||
|             dolphin_deed(dolphin, DolphinDeedIButtonRead); |  | ||||||
|         } else if(event->key == InputKeyOk) { |  | ||||||
|             dolphin_save(dolphin); |  | ||||||
|         } else { |  | ||||||
|             return false; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if(event->key == InputKeyBack) { |  | ||||||
|         view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     return true; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| Dolphin* dolphin_alloc() { |  | ||||||
|     Dolphin* dolphin = furi_alloc(sizeof(Dolphin)); |  | ||||||
|     // Message queue
 |  | ||||||
|     dolphin->event_queue = osMessageQueueNew(8, sizeof(DolphinEvent), NULL); |  | ||||||
|     furi_check(dolphin->event_queue); |  | ||||||
|     // State
 |  | ||||||
|     dolphin->state = dolphin_state_alloc(); |  | ||||||
|     // Menu
 |  | ||||||
|     dolphin->menu_vm = furi_record_open("menu"); |  | ||||||
|     // Scene thread
 |  | ||||||
|     dolphin->scene_thread = furi_thread_alloc(); |  | ||||||
|     // GUI
 |  | ||||||
|     dolphin->gui = furi_record_open("gui"); |  | ||||||
|     // Dispatcher
 |  | ||||||
|     dolphin->idle_view_dispatcher = view_dispatcher_alloc(); |  | ||||||
| 
 |  | ||||||
|     // First start View
 |  | ||||||
|     dolphin->idle_view_first_start = view_alloc(); |  | ||||||
|     view_allocate_model( |  | ||||||
|         dolphin->idle_view_first_start, ViewModelTypeLockFree, sizeof(DolphinViewFirstStartModel)); |  | ||||||
|     view_set_context(dolphin->idle_view_first_start, dolphin); |  | ||||||
|     view_set_draw_callback(dolphin->idle_view_first_start, dolphin_view_first_start_draw); |  | ||||||
|     view_set_input_callback(dolphin->idle_view_first_start, dolphin_view_first_start_input); |  | ||||||
|     view_dispatcher_add_view( |  | ||||||
|         dolphin->idle_view_dispatcher, DolphinViewFirstStart, dolphin->idle_view_first_start); |  | ||||||
| 
 |  | ||||||
|     // Main Idle View
 |  | ||||||
|     dolphin->idle_view_main = view_alloc(); |  | ||||||
|     view_set_context(dolphin->idle_view_main, dolphin); |  | ||||||
|     view_allocate_model( |  | ||||||
|         dolphin->idle_view_main, ViewModelTypeLockFree, sizeof(DolphinViewMainModel)); |  | ||||||
| 
 |  | ||||||
|     view_set_draw_callback(dolphin->idle_view_main, dolphin_view_idle_main_draw); |  | ||||||
|     view_set_input_callback(dolphin->idle_view_main, dolphin_view_idle_main_input); |  | ||||||
|     view_dispatcher_add_view( |  | ||||||
|         dolphin->idle_view_dispatcher, DolphinViewIdleMain, dolphin->idle_view_main); |  | ||||||
| 
 |  | ||||||
|     // Lock Menu View
 |  | ||||||
|     dolphin->view_lockmenu = view_alloc(); |  | ||||||
|     view_set_context(dolphin->view_lockmenu, dolphin); |  | ||||||
|     view_allocate_model( |  | ||||||
|         dolphin->view_lockmenu, ViewModelTypeLockFree, sizeof(DolphinViewLockMenuModel)); |  | ||||||
|     view_set_draw_callback(dolphin->view_lockmenu, dolphin_view_lockmenu_draw); |  | ||||||
|     view_set_input_callback(dolphin->view_lockmenu, dolphin_view_lockmenu_input); |  | ||||||
|     view_set_previous_callback(dolphin->view_lockmenu, dolphin_view_idle_back); |  | ||||||
|     view_dispatcher_add_view( |  | ||||||
|         dolphin->idle_view_dispatcher, DolphinViewLockMenu, dolphin->view_lockmenu); |  | ||||||
| 
 |  | ||||||
|     // default doors xpos
 |  | ||||||
|     with_view_model( |  | ||||||
|         dolphin->view_lockmenu, (DolphinViewLockMenuModel * model) { |  | ||||||
|             model->door_left_x = -57; // defaults
 |  | ||||||
|             model->door_right_x = 115; // defaults
 |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|     dolphin->timeout_timer = |  | ||||||
|         osTimerNew(lock_menu_refresh_handler, osTimerPeriodic, dolphin->event_queue, NULL); |  | ||||||
| 
 |  | ||||||
|     // Stats Idle View
 |  | ||||||
|     dolphin->idle_view_dolphin_stats = view_alloc(); |  | ||||||
|     view_set_context(dolphin->idle_view_dolphin_stats, dolphin); |  | ||||||
|     view_allocate_model( |  | ||||||
|         dolphin->idle_view_dolphin_stats, ViewModelTypeLockFree, sizeof(DolphinViewStatsModel)); |  | ||||||
|     view_set_draw_callback(dolphin->idle_view_dolphin_stats, dolphin_view_idle_down_draw); |  | ||||||
|     view_set_input_callback(dolphin->idle_view_dolphin_stats, dolphin_view_idle_down_input); |  | ||||||
|     view_set_previous_callback(dolphin->idle_view_dolphin_stats, dolphin_view_idle_back); |  | ||||||
|     view_dispatcher_add_view( |  | ||||||
|         dolphin->idle_view_dispatcher, DolphinViewStats, dolphin->idle_view_dolphin_stats); |  | ||||||
|     // HW Mismatch
 |  | ||||||
|     dolphin->view_hw_mismatch = view_alloc(); |  | ||||||
|     view_set_draw_callback(dolphin->view_hw_mismatch, dolphin_view_hw_mismatch_draw); |  | ||||||
|     view_set_previous_callback(dolphin->view_hw_mismatch, dolphin_view_idle_back); |  | ||||||
|     view_dispatcher_add_view( |  | ||||||
|         dolphin->idle_view_dispatcher, DolphinViewHwMismatch, dolphin->view_hw_mismatch); |  | ||||||
| 
 |  | ||||||
|     // Lock icon
 |  | ||||||
|     dolphin->lock_icon = icon_animation_alloc(&I_Lock_8x8); |  | ||||||
|     dolphin->lock_viewport = view_port_alloc(); |  | ||||||
|     view_port_set_width(dolphin->lock_viewport, icon_animation_get_width(dolphin->lock_icon)); |  | ||||||
|     view_port_draw_callback_set(dolphin->lock_viewport, lock_icon_callback, dolphin); |  | ||||||
|     view_port_enabled_set(dolphin->lock_viewport, false); |  | ||||||
| 
 |  | ||||||
|     // Main screen animation
 |  | ||||||
|     dolphin_scene_handler_set_scene(dolphin, idle_scenes[random() % COUNT_OF(idle_scenes)]); |  | ||||||
| 
 |  | ||||||
|     view_dispatcher_attach_to_gui( |  | ||||||
|         dolphin->idle_view_dispatcher, dolphin->gui, ViewDispatcherTypeWindow); |  | ||||||
|     gui_add_view_port(dolphin->gui, dolphin->lock_viewport, GuiLayerStatusBarLeft); |  | ||||||
| 
 |  | ||||||
|     return dolphin; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void dolphin_free(Dolphin* dolphin) { |  | ||||||
|     furi_assert(dolphin); |  | ||||||
| 
 |  | ||||||
|     gui_remove_view_port(dolphin->gui, dolphin->lock_viewport); |  | ||||||
|     view_port_free(dolphin->lock_viewport); |  | ||||||
|     icon_animation_free(dolphin->lock_icon); |  | ||||||
| 
 |  | ||||||
|     osTimerDelete(dolphin->timeout_timer); |  | ||||||
| 
 |  | ||||||
|     view_dispatcher_free(dolphin->idle_view_dispatcher); |  | ||||||
| 
 |  | ||||||
|     furi_record_close("gui"); |  | ||||||
|     dolphin->gui = NULL; |  | ||||||
| 
 |  | ||||||
|     furi_thread_free(dolphin->scene_thread); |  | ||||||
| 
 |  | ||||||
|     furi_record_close("menu"); |  | ||||||
|     dolphin->menu_vm = NULL; |  | ||||||
| 
 |  | ||||||
|     dolphin_state_free(dolphin->state); |  | ||||||
| 
 |  | ||||||
|     osMessageQueueDelete(dolphin->event_queue); |  | ||||||
| 
 |  | ||||||
|     free(dolphin); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void dolphin_save(Dolphin* dolphin) { | void dolphin_save(Dolphin* dolphin) { | ||||||
| @ -401,56 +21,53 @@ void dolphin_deed(Dolphin* dolphin, DolphinDeed deed) { | |||||||
|     furi_check(osMessageQueuePut(dolphin->event_queue, &event, 0, osWaitForever) == osOK); |     furi_check(osMessageQueuePut(dolphin->event_queue, &event, 0, osWaitForever) == osOK); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| int32_t dolphin_srv() { | DolphinDeedWeight dolphin_stats(Dolphin* dolphin) { | ||||||
|  |     DolphinDeedWeight stats; | ||||||
|  |     stats.butthurt = dolphin_state_get_butthurt(dolphin->state); | ||||||
|  |     stats.icounter = dolphin_state_get_icounter(dolphin->state); | ||||||
|  | 
 | ||||||
|  |     return stats; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | Dolphin* dolphin_alloc() { | ||||||
|  |     Dolphin* dolphin = furi_alloc(sizeof(Dolphin)); | ||||||
|  | 
 | ||||||
|  |     dolphin->state = dolphin_state_alloc(); | ||||||
|  |     dolphin->event_queue = osMessageQueueNew(8, sizeof(DolphinEvent), NULL); | ||||||
|  | 
 | ||||||
|  |     return dolphin; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | void dolphin_free(Dolphin* dolphin) { | ||||||
|  |     furi_assert(dolphin); | ||||||
|  | 
 | ||||||
|  |     dolphin_state_free(dolphin->state); | ||||||
|  |     osMessageQueueDelete(dolphin->event_queue); | ||||||
|  | 
 | ||||||
|  |     free(dolphin); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | int32_t dolphin_srv(void* p) { | ||||||
|     Dolphin* dolphin = dolphin_alloc(); |     Dolphin* dolphin = dolphin_alloc(); | ||||||
| 
 |  | ||||||
|     if(dolphin_state_load(dolphin->state)) { |  | ||||||
|         view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); |  | ||||||
|     } else { |  | ||||||
|         view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewFirstStart); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     with_view_model( |  | ||||||
|         dolphin->idle_view_dolphin_stats, (DolphinViewStatsModel * model) { |  | ||||||
|             model->icounter = dolphin_state_get_icounter(dolphin->state); |  | ||||||
|             model->butthurt = dolphin_state_get_butthurt(dolphin->state); |  | ||||||
|             return true; |  | ||||||
|         }); |  | ||||||
| 
 |  | ||||||
|     furi_record_create("dolphin", dolphin); |     furi_record_create("dolphin", dolphin); | ||||||
| 
 | 
 | ||||||
|     if(!furi_hal_version_do_i_belong_here()) { |  | ||||||
|         view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewHwMismatch); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     DolphinEvent event; |     DolphinEvent event; | ||||||
|     while(1) { |     while(1) { | ||||||
|         furi_check(osMessageQueueGet(dolphin->event_queue, &event, NULL, osWaitForever) == osOK); |         furi_check(osMessageQueueGet(dolphin->event_queue, &event, NULL, osWaitForever) == osOK); | ||||||
| 
 |         switch(event.type) { | ||||||
|         DolphinViewLockMenuModel* lock_model = view_get_model(dolphin->view_lockmenu); |         case DolphinEventTypeDeed: | ||||||
| 
 |  | ||||||
|         if(lock_model->locked && lock_model->exit_timeout == 0 && |  | ||||||
|            osTimerIsRunning(dolphin->timeout_timer)) { |  | ||||||
|             osTimerStop(dolphin->timeout_timer); |  | ||||||
|             osDelay(1); // smol enterprise delay
 |  | ||||||
|             view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewIdleMain); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(event.type == DolphinEventTypeTick) { |  | ||||||
|             view_commit_model(dolphin->view_lockmenu, true); |  | ||||||
| 
 |  | ||||||
|         } else if(event.type == DolphinEventTypeDeed) { |  | ||||||
|             dolphin_state_on_deed(dolphin->state, event.deed); |             dolphin_state_on_deed(dolphin->state, event.deed); | ||||||
|             with_view_model( |             break; | ||||||
|                 dolphin->idle_view_dolphin_stats, (DolphinViewStatsModel * model) { | 
 | ||||||
|                     model->icounter = dolphin_state_get_icounter(dolphin->state); |         case DolphinEventTypeSave: | ||||||
|                     model->butthurt = dolphin_state_get_butthurt(dolphin->state); |  | ||||||
|                     return true; |  | ||||||
|                 }); |  | ||||||
|         } else if(event.type == DolphinEventTypeSave) { |  | ||||||
|             dolphin_state_save(dolphin->state); |             dolphin_state_save(dolphin->state); | ||||||
|  |             break; | ||||||
|  | 
 | ||||||
|  |         default: | ||||||
|  |             break; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|     dolphin_free(dolphin); |     dolphin_free(dolphin); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
|  | |||||||
| @ -1,11 +1,30 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "dolphin_deed.h" | #include "helpers/dolphin_deed.h" | ||||||
| 
 | 
 | ||||||
| typedef struct Dolphin Dolphin; | typedef struct Dolphin Dolphin; | ||||||
| 
 | 
 | ||||||
|  | /* Load Dolphin state
 | ||||||
|  |  * Thread safe | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | bool dolphin_load(Dolphin* dolphin); | ||||||
|  | 
 | ||||||
| /* Deed complete notification. Call it on deed completion.
 | /* Deed complete notification. Call it on deed completion.
 | ||||||
|  * See dolphin_deed.h for available deeds. In futures it will become part of assets. |  * See dolphin_deed.h for available deeds. In futures it will become part of assets. | ||||||
|  * Thread safe |  * Thread safe | ||||||
|  */ |  */ | ||||||
|  | 
 | ||||||
| void dolphin_deed(Dolphin* dolphin, DolphinDeed deed); | void dolphin_deed(Dolphin* dolphin, DolphinDeed deed); | ||||||
|  | 
 | ||||||
|  | /* Save Dolphin state (write to permanent memory)
 | ||||||
|  |  * Thread safe | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | void dolphin_save(Dolphin* dolphin); | ||||||
|  | 
 | ||||||
|  | /* Retrieve dolphin's icounter and butthurt values
 | ||||||
|  |  * Thread safe | ||||||
|  |  */ | ||||||
|  | 
 | ||||||
|  | DolphinDeedWeight dolphin_stats(Dolphin* dolphin); | ||||||
| @ -1,22 +1,10 @@ | |||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include "dolphin.h" |  | ||||||
| #include "dolphin_state.h" |  | ||||||
| #include "dolphin_views.h" |  | ||||||
| 
 |  | ||||||
| #include <furi.h> | #include <furi.h> | ||||||
| #include <furi-hal.h> | #include <furi-hal.h> | ||||||
| #include <gui/gui.h> |  | ||||||
| #include <gui/view_dispatcher.h> |  | ||||||
| #include <gui/canvas.h> |  | ||||||
| #include <menu/menu.h> |  | ||||||
| 
 | 
 | ||||||
| #include <assets_icons.h> | #include "dolphin.h" | ||||||
| #include <stdint.h> | #include "helpers/dolphin_state.h" | ||||||
| 
 |  | ||||||
| #define UNLOCK_RST_TIMEOUT 500 // keypress counter reset timeout (ms)
 |  | ||||||
| #define HINT_TIMEOUT_L 3 // low refresh rate timeout (app ticks)
 |  | ||||||
| #define HINT_TIMEOUT_H 40 // high refresh rate timeout (app ticks)
 |  | ||||||
| 
 | 
 | ||||||
| typedef enum { | typedef enum { | ||||||
|     DolphinEventTypeDeed, |     DolphinEventTypeDeed, | ||||||
| @ -32,36 +20,12 @@ typedef struct { | |||||||
| } DolphinEvent; | } DolphinEvent; | ||||||
| 
 | 
 | ||||||
| struct Dolphin { | struct Dolphin { | ||||||
|     // Internal message queue
 |  | ||||||
|     osMessageQueueId_t event_queue; |  | ||||||
|     // State
 |     // State
 | ||||||
|     DolphinState* state; |     DolphinState* state; | ||||||
|     // Menu
 |     // Queue
 | ||||||
|     ValueMutex* menu_vm; |     osMessageQueueId_t event_queue; | ||||||
|     // Scene
 |  | ||||||
|     FuriThread* scene_thread; |  | ||||||
|     // GUI
 |  | ||||||
|     Gui* gui; |  | ||||||
|     ViewDispatcher* idle_view_dispatcher; |  | ||||||
|     View* idle_view_first_start; |  | ||||||
|     View* idle_view_main; |  | ||||||
|     View* idle_view_dolphin_stats; |  | ||||||
|     View* view_hw_mismatch; |  | ||||||
|     View* view_lockmenu; |  | ||||||
|     ViewPort* lock_viewport; |  | ||||||
|     IconAnimation* lock_icon; |  | ||||||
| 
 |  | ||||||
|     bool locked; |  | ||||||
|     uint8_t lock_count; |  | ||||||
|     uint32_t lock_lastpress; |  | ||||||
|     osTimerId_t timeout_timer; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| Dolphin* dolphin_alloc(); | Dolphin* dolphin_alloc(); | ||||||
| 
 | 
 | ||||||
| void dolphin_free(Dolphin* dolphin); | void dolphin_free(Dolphin* dolphin); | ||||||
| 
 |  | ||||||
| /* Save Dolphin state (write to permanent memory)
 |  | ||||||
|  * Thread safe |  | ||||||
|  */ |  | ||||||
| void dolphin_save(Dolphin* dolphin); |  | ||||||
|  | |||||||
| @ -1,197 +0,0 @@ | |||||||
| #include "dolphin_views.h" |  | ||||||
| #include <gui/view.h> |  | ||||||
| #include <gui/gui.h> |  | ||||||
| #include <gui/elements.h> |  | ||||||
| #include <furi-hal.h> |  | ||||||
| #include <furi-hal-version.h> |  | ||||||
| 
 |  | ||||||
| static char* Lockmenu_Items[3] = {"Lock", "Set PIN", "DUMB mode"}; |  | ||||||
| 
 |  | ||||||
| void dolphin_view_first_start_draw(Canvas* canvas, void* model) { |  | ||||||
|     DolphinViewFirstStartModel* m = model; |  | ||||||
|     canvas_clear(canvas); |  | ||||||
|     canvas_set_color(canvas, ColorBlack); |  | ||||||
|     canvas_set_font(canvas, FontSecondary); |  | ||||||
|     uint8_t width = canvas_width(canvas); |  | ||||||
|     uint8_t height = canvas_height(canvas); |  | ||||||
|     const char* my_name = furi_hal_version_get_name_ptr(); |  | ||||||
|     if(m->page == 0) { |  | ||||||
|         canvas_draw_icon(canvas, 0, height - 48, &I_DolphinFirstStart0_70x53); |  | ||||||
|         elements_multiline_text_framed(canvas, 75, 20, "Hey m8,\npress > to\ncontinue"); |  | ||||||
|     } else if(m->page == 1) { |  | ||||||
|         canvas_draw_icon(canvas, 0, height - 48, &I_DolphinFirstStart1_59x53); |  | ||||||
|         elements_multiline_text_framed(canvas, 64, 20, "First Of All,\n...      >"); |  | ||||||
|     } else if(m->page == 2) { |  | ||||||
|         canvas_draw_icon(canvas, 0, height - 48, &I_DolphinFirstStart2_59x51); |  | ||||||
|         elements_multiline_text_framed(canvas, 64, 20, "Thank you\nfor your\nsupport! >"); |  | ||||||
|     } else if(m->page == 3) { |  | ||||||
|         canvas_draw_icon(canvas, width - 57, height - 48, &I_DolphinFirstStart3_57x48); |  | ||||||
|         elements_multiline_text_framed(canvas, 0, 20, "Kickstarter\ncampaign\nwas INSANE! >"); |  | ||||||
|     } else if(m->page == 4) { |  | ||||||
|         canvas_draw_icon(canvas, width - 67, height - 50, &I_DolphinFirstStart4_67x53); |  | ||||||
|         elements_multiline_text_framed(canvas, 0, 17, "Now\nallow me\nto introduce\nmyself >"); |  | ||||||
|     } else if(m->page == 5) { |  | ||||||
|         char buf[64]; |  | ||||||
|         snprintf( |  | ||||||
|             buf, |  | ||||||
|             64, |  | ||||||
|             "%s %s%s", |  | ||||||
|             "I am", |  | ||||||
|             my_name ? my_name : "Unknown", |  | ||||||
|             ",\ncyberdolphin\nliving in your\npocket >"); |  | ||||||
|         canvas_draw_icon(canvas, 0, height - 48, &I_DolphinFirstStart5_54x49); |  | ||||||
|         elements_multiline_text_framed(canvas, 60, 17, buf); |  | ||||||
|     } else if(m->page == 6) { |  | ||||||
|         canvas_draw_icon(canvas, 0, height - 48, &I_DolphinFirstStart6_58x54); |  | ||||||
|         elements_multiline_text_framed( |  | ||||||
|             canvas, 63, 17, "I can grow\nsmart'n'cool\nif you use me\noften >"); |  | ||||||
|     } else if(m->page == 7) { |  | ||||||
|         canvas_draw_icon(canvas, width - 61, height - 48, &I_DolphinFirstStart7_61x51); |  | ||||||
|         elements_multiline_text_framed( |  | ||||||
|             canvas, 0, 17, "As long as\nyou read, write\nand emulate >"); |  | ||||||
|     } else if(m->page == 8) { |  | ||||||
|         canvas_draw_icon(canvas, width - 56, height - 48, &I_DolphinFirstStart8_56x51); |  | ||||||
|         elements_multiline_text_framed( |  | ||||||
|             canvas, 0, 17, "You can check\nmy level and\nmood in the\nPassport menu"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void dolphin_view_idle_main_draw(Canvas* canvas, void* model) { |  | ||||||
|     canvas_clear(canvas); |  | ||||||
|     DolphinViewMainModel* m = model; |  | ||||||
|     if(m->animation) { |  | ||||||
|         canvas_draw_icon_animation(canvas, 0, -3, m->animation); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     if(m->hint_timeout) { |  | ||||||
|         m->hint_timeout--; |  | ||||||
|         if(m->locked) { |  | ||||||
|             canvas_draw_icon(canvas, 13, 5, &I_LockPopup_100x49); |  | ||||||
|             elements_multiline_text(canvas, 65, 20, "To unlock\npress:"); |  | ||||||
|         } else { |  | ||||||
|             canvas_set_font(canvas, FontPrimary); |  | ||||||
|             elements_multiline_text_framed(canvas, 42, 30, "Unlocked"); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void dolphin_view_lockmenu_draw(Canvas* canvas, void* model) { |  | ||||||
|     DolphinViewLockMenuModel* m = model; |  | ||||||
|     canvas_clear(canvas); |  | ||||||
|     canvas_set_color(canvas, ColorBlack); |  | ||||||
|     canvas_draw_icon(canvas, m->door_left_x, 0, &I_DoorLeft_70x55); |  | ||||||
|     canvas_draw_icon(canvas, m->door_right_x, 0, &I_DoorRight_70x55); |  | ||||||
|     canvas_set_font(canvas, FontSecondary); |  | ||||||
| 
 |  | ||||||
|     if(m->locked) { |  | ||||||
|         m->exit_timeout--; |  | ||||||
| 
 |  | ||||||
|         m->door_left_x = CLAMP(m->door_left_x + 5, 0, -57); |  | ||||||
|         m->door_right_x = CLAMP(m->door_right_x - 5, 115, 60); |  | ||||||
| 
 |  | ||||||
|         if(m->door_left_x > -10) { |  | ||||||
|             canvas_set_font(canvas, FontPrimary); |  | ||||||
|             elements_multiline_text_framed(canvas, 42, 30, "Locked"); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|     } else { |  | ||||||
|         if(m->door_left_x == -57) { |  | ||||||
|             for(uint8_t i = 0; i < 3; ++i) { |  | ||||||
|                 canvas_draw_str_aligned( |  | ||||||
|                     canvas, |  | ||||||
|                     64, |  | ||||||
|                     13 + (i * 17), |  | ||||||
|                     AlignCenter, |  | ||||||
|                     AlignCenter, |  | ||||||
|                     (m->hint_timeout && m->idx == i) ? "Not implemented" : Lockmenu_Items[i]); |  | ||||||
|                 if(m->idx == i) elements_frame(canvas, 15, 5 + (i * 17), 98, 15); |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         if(m->hint_timeout) { |  | ||||||
|             m->hint_timeout--; |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void dolphin_view_idle_down_draw(Canvas* canvas, void* model) { |  | ||||||
|     DolphinViewStatsModel* m = model; |  | ||||||
|     const Version* ver; |  | ||||||
|     char buffer[64]; |  | ||||||
| 
 |  | ||||||
|     static const char* headers[] = {"FW Version info:", "Boot Version info:", "Dolphin info:"}; |  | ||||||
| 
 |  | ||||||
|     canvas_set_color(canvas, ColorBlack); |  | ||||||
|     canvas_set_font(canvas, FontPrimary); |  | ||||||
|     canvas_draw_str(canvas, 2, 13, headers[m->screen]); |  | ||||||
|     canvas_set_font(canvas, FontSecondary); |  | ||||||
| 
 |  | ||||||
|     if(m->screen != DolphinViewStatsMeta) { |  | ||||||
|         // Hardware version
 |  | ||||||
|         const char* my_name = furi_hal_version_get_name_ptr(); |  | ||||||
|         snprintf( |  | ||||||
|             buffer, |  | ||||||
|             sizeof(buffer), |  | ||||||
|             "HW: %d.F%dB%dC%d %s", |  | ||||||
|             furi_hal_version_get_hw_version(), |  | ||||||
|             furi_hal_version_get_hw_target(), |  | ||||||
|             furi_hal_version_get_hw_body(), |  | ||||||
|             furi_hal_version_get_hw_connect(), |  | ||||||
|             my_name ? my_name : "Unknown"); |  | ||||||
|         canvas_draw_str(canvas, 5, 23, buffer); |  | ||||||
| 
 |  | ||||||
|         ver = m->screen == DolphinViewStatsBoot ? furi_hal_version_get_boot_version() : |  | ||||||
|                                                   furi_hal_version_get_firmware_version(); |  | ||||||
| 
 |  | ||||||
|         if(!ver) { |  | ||||||
|             canvas_draw_str(canvas, 5, 33, "No info"); |  | ||||||
|             return; |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|         snprintf( |  | ||||||
|             buffer, |  | ||||||
|             sizeof(buffer), |  | ||||||
|             "%s [%s]", |  | ||||||
|             version_get_version(ver), |  | ||||||
|             version_get_builddate(ver)); |  | ||||||
|         canvas_draw_str(canvas, 5, 33, buffer); |  | ||||||
| 
 |  | ||||||
|         snprintf( |  | ||||||
|             buffer, |  | ||||||
|             sizeof(buffer), |  | ||||||
|             "%s [%s]", |  | ||||||
|             version_get_githash(ver), |  | ||||||
|             version_get_gitbranchnum(ver)); |  | ||||||
|         canvas_draw_str(canvas, 5, 43, buffer); |  | ||||||
| 
 |  | ||||||
|         snprintf( |  | ||||||
|             buffer, sizeof(buffer), "[%s] %s", version_get_target(ver), version_get_gitbranch(ver)); |  | ||||||
|         canvas_draw_str(canvas, 5, 53, buffer); |  | ||||||
| 
 |  | ||||||
|     } else { |  | ||||||
|         char buffer[64]; |  | ||||||
|         canvas_set_font(canvas, FontSecondary); |  | ||||||
|         snprintf(buffer, 64, "Icounter: %ld", m->icounter); |  | ||||||
|         canvas_draw_str(canvas, 5, 30, buffer); |  | ||||||
|         snprintf(buffer, 64, "Butthurt: %ld", m->butthurt); |  | ||||||
|         canvas_draw_str(canvas, 5, 40, buffer); |  | ||||||
|         canvas_draw_str(canvas, 0, 53, "[< >] icounter value   [ok] save"); |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void dolphin_view_hw_mismatch_draw(Canvas* canvas, void* model) { |  | ||||||
|     canvas_clear(canvas); |  | ||||||
|     canvas_set_color(canvas, ColorBlack); |  | ||||||
|     canvas_set_font(canvas, FontPrimary); |  | ||||||
|     canvas_draw_str(canvas, 2, 15, "!!!! HW Mismatch !!!!"); |  | ||||||
| 
 |  | ||||||
|     char buffer[64]; |  | ||||||
|     canvas_set_font(canvas, FontSecondary); |  | ||||||
|     snprintf(buffer, 64, "HW target: F%d", furi_hal_version_get_hw_target()); |  | ||||||
|     canvas_draw_str(canvas, 5, 27, buffer); |  | ||||||
|     canvas_draw_str(canvas, 5, 38, "FW target: " TARGET); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| uint32_t dolphin_view_idle_back(void* context) { |  | ||||||
|     return DolphinViewIdleMain; |  | ||||||
| } |  | ||||||
| @ -1,67 +0,0 @@ | |||||||
| #pragma once |  | ||||||
| 
 |  | ||||||
| #include <stdint.h> |  | ||||||
| #include <stdbool.h> |  | ||||||
| #include <gui/canvas.h> |  | ||||||
| #include <input/input.h> |  | ||||||
| #include <furi.h> |  | ||||||
| 
 |  | ||||||
| // Idle screen
 |  | ||||||
| typedef enum { |  | ||||||
|     DolphinViewIdleMain, |  | ||||||
|     DolphinViewFirstStart, |  | ||||||
|     DolphinViewStats, |  | ||||||
|     DolphinViewHwMismatch, |  | ||||||
|     DolphinViewLockMenu, |  | ||||||
| } DolphinViewIdle; |  | ||||||
| 
 |  | ||||||
| // Debug info
 |  | ||||||
| typedef enum { |  | ||||||
|     DolphinViewStatsFw, |  | ||||||
|     DolphinViewStatsBoot, |  | ||||||
|     DolphinViewStatsMeta, |  | ||||||
|     DolphinViewStatsTotalCount, |  | ||||||
| } DolphinViewStatsScreens; |  | ||||||
| 
 |  | ||||||
| typedef struct { |  | ||||||
|     uint32_t page; |  | ||||||
| } DolphinViewFirstStartModel; |  | ||||||
| 
 |  | ||||||
| void dolphin_view_first_start_draw(Canvas* canvas, void* model); |  | ||||||
| bool dolphin_view_first_start_input(InputEvent* event, void* context); |  | ||||||
| 
 |  | ||||||
| typedef struct { |  | ||||||
|     uint32_t icounter; |  | ||||||
|     uint32_t butthurt; |  | ||||||
|     DolphinViewStatsScreens screen; |  | ||||||
| } DolphinViewStatsModel; |  | ||||||
| 
 |  | ||||||
| typedef struct { |  | ||||||
|     uint8_t idx; |  | ||||||
|     int8_t door_left_x; |  | ||||||
|     int8_t door_right_x; |  | ||||||
|     uint8_t exit_timeout; |  | ||||||
|     uint8_t hint_timeout; |  | ||||||
| 
 |  | ||||||
|     bool locked; |  | ||||||
| } DolphinViewLockMenuModel; |  | ||||||
| 
 |  | ||||||
| typedef struct { |  | ||||||
|     IconAnimation* animation; |  | ||||||
|     uint8_t scene_num; |  | ||||||
|     uint8_t hint_timeout; |  | ||||||
|     bool locked; |  | ||||||
| } DolphinViewMainModel; |  | ||||||
| 
 |  | ||||||
| void dolphin_view_idle_main_draw(Canvas* canvas, void* model); |  | ||||||
| bool dolphin_view_idle_main_input(InputEvent* event, void* context); |  | ||||||
| 
 |  | ||||||
| void dolphin_view_idle_up_draw(Canvas* canvas, void* model); |  | ||||||
| 
 |  | ||||||
| void dolphin_view_lockmenu_draw(Canvas* canvas, void* model); |  | ||||||
| 
 |  | ||||||
| void dolphin_view_idle_down_draw(Canvas* canvas, void* model); |  | ||||||
| 
 |  | ||||||
| void dolphin_view_hw_mismatch_draw(Canvas* canvas, void* model); |  | ||||||
| 
 |  | ||||||
| uint32_t dolphin_view_idle_back(void* context); |  | ||||||
| @ -16,6 +16,7 @@ typedef enum { | |||||||
| 
 | 
 | ||||||
| typedef struct { | typedef struct { | ||||||
|     int32_t icounter; // how many icounter get by Deed
 |     int32_t icounter; // how many icounter get by Deed
 | ||||||
|  |     int32_t butthurt; // how many icounter get by Deed
 | ||||||
|     uint32_t limit_value; // how many deeds in limit interval
 |     uint32_t limit_value; // how many deeds in limit interval
 | ||||||
|     uint32_t limit_interval; // interval, in minutes
 |     uint32_t limit_interval; // interval, in minutes
 | ||||||
| } DolphinDeedWeight; | } DolphinDeedWeight; | ||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 its your bedtime
						its your bedtime