diff --git a/applications/applications.c b/applications/applications.c index 6c857b20..a33c540d 100755 --- a/applications/applications.c +++ b/applications/applications.c @@ -14,6 +14,7 @@ extern int32_t notification_srv(void* p); extern int32_t power_observer_srv(void* p); extern int32_t power_srv(void* p); extern int32_t storage_srv(void* p); +extern int32_t desktop_srv(void* p); // Apps 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 storage_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 power_settings_app(void* p); @@ -73,6 +75,10 @@ const FlipperApplication FLIPPER_SERVICES[] = { {.app = dolphin_srv, .name = "Dolphin", .stack_size = 1024, .icon = NULL}, #endif +#ifdef SRV_DESKTOP + {.app = desktop_srv, .name = "Desktop", .stack_size = 1024, .icon = NULL}, +#endif + #ifdef SRV_GUI {.app = gui_srv, .name = "Gui", .stack_size = 8192, .icon = NULL}, #endif @@ -282,6 +288,10 @@ const FlipperApplication FLIPPER_SETTINGS_APPS[] = { {.app = power_settings_app, .name = "Power", .stack_size = 1024, .icon = NULL}, #endif +#ifdef APP_DESKTOP + {.app = desktop_settings_app, .name = "Desktop", .stack_size = 1024, .icon = NULL}, +#endif + #ifdef APP_ABOUT {.app = about_settings_app, .name = "About", .stack_size = 1024, .icon = NULL}, #endif diff --git a/applications/applications.mk b/applications/applications.mk index 586439f5..3b92a723 100644 --- a/applications/applications.mk +++ b/applications/applications.mk @@ -25,6 +25,7 @@ SRV_POWER_OBSERVER = 1 SRV_STORAGE = 1 # Apps +SRV_DESKTOP = 1 APP_ARCHIVE = 1 APP_GPIO_TEST = 1 APP_IBUTTON = 1 @@ -95,6 +96,12 @@ ifeq ($(APP_UNIT_TESTS), 1) CFLAGS += -DAPP_UNIT_TESTS endif +SRV_DESKTOP ?= 0 +ifeq ($(SRV_DESKTOP), 1) +CFLAGS += -DSRV_DESKTOP +SRV_DESKTOP = 1 +endif + APP_ARCHIVE ?= 0 ifeq ($(APP_NFC), 1) CFLAGS += -DAPP_ARCHIVE diff --git a/applications/desktop/desktop.c b/applications/desktop/desktop.c new file mode 100644 index 00000000..a658bcaa --- /dev/null +++ b/applications/desktop/desktop.c @@ -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; +} diff --git a/applications/desktop/desktop.h b/applications/desktop/desktop.h new file mode 100644 index 00000000..f5608207 --- /dev/null +++ b/applications/desktop/desktop.h @@ -0,0 +1,3 @@ +#pragma once + +typedef struct Desktop Desktop; diff --git a/applications/desktop/desktop_i.h b/applications/desktop/desktop_i.h new file mode 100644 index 00000000..05ba4793 --- /dev/null +++ b/applications/desktop/desktop_i.h @@ -0,0 +1,59 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#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); diff --git a/applications/desktop/desktop_settings/desktop_settings.c b/applications/desktop/desktop_settings/desktop_settings.c new file mode 100644 index 00000000..5e170a09 --- /dev/null +++ b/applications/desktop/desktop_settings/desktop_settings.c @@ -0,0 +1,49 @@ +#include +#include +#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; +} diff --git a/applications/desktop/desktop_settings/desktop_settings.h b/applications/desktop/desktop_settings/desktop_settings.h new file mode 100644 index 00000000..a2aead82 --- /dev/null +++ b/applications/desktop/desktop_settings/desktop_settings.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +#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); diff --git a/applications/desktop/desktop_settings/desktop_settings_app.c b/applications/desktop/desktop_settings/desktop_settings_app.c new file mode 100644 index 00000000..3c7610f5 --- /dev/null +++ b/applications/desktop/desktop_settings/desktop_settings_app.c @@ -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; +} diff --git a/applications/desktop/desktop_settings/desktop_settings_app.h b/applications/desktop/desktop_settings/desktop_settings_app.h new file mode 100644 index 00000000..ba381cde --- /dev/null +++ b/applications/desktop/desktop_settings/desktop_settings_app.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +#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; diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene.c b/applications/desktop/desktop_settings/scenes/desktop_settings_scene.c new file mode 100644 index 00000000..03e73e67 --- /dev/null +++ b/applications/desktop/desktop_settings/scenes/desktop_settings_scene.c @@ -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, +}; diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene.h b/applications/desktop/desktop_settings/scenes/desktop_settings_scene.h new file mode 100644 index 00000000..18fbb2c6 --- /dev/null +++ b/applications/desktop/desktop_settings/scenes/desktop_settings_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// 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 diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_config.h b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_config.h new file mode 100644 index 00000000..a2abec0a --- /dev/null +++ b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_config.h @@ -0,0 +1,2 @@ +ADD_SCENE(desktop_settings, start, Start) +ADD_SCENE(desktop_settings, favorite, Favorite) diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_favorite.c b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_favorite.c new file mode 100644 index 00000000..e8559017 --- /dev/null +++ b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_favorite.c @@ -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); +} diff --git a/applications/desktop/desktop_settings/scenes/desktop_settings_scene_start.c b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_start.c new file mode 100755 index 00000000..33d66d0c --- /dev/null +++ b/applications/desktop/desktop_settings/scenes/desktop_settings_scene_start.c @@ -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); +} diff --git a/applications/desktop/scenes/desktop_scene.c b/applications/desktop/scenes/desktop_scene.c new file mode 100644 index 00000000..8c9b5838 --- /dev/null +++ b/applications/desktop/scenes/desktop_scene.c @@ -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, +}; diff --git a/applications/desktop/scenes/desktop_scene.h b/applications/desktop/scenes/desktop_scene.h new file mode 100644 index 00000000..34b36eaf --- /dev/null +++ b/applications/desktop/scenes/desktop_scene.h @@ -0,0 +1,29 @@ +#pragma once + +#include + +// 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 diff --git a/applications/desktop/scenes/desktop_scene_config.h b/applications/desktop/scenes/desktop_scene_config.h new file mode 100644 index 00000000..067de7c4 --- /dev/null +++ b/applications/desktop/scenes/desktop_scene_config.h @@ -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) diff --git a/applications/desktop/scenes/desktop_scene_debug.c b/applications/desktop/scenes/desktop_scene_debug.c new file mode 100644 index 00000000..4a490f2a --- /dev/null +++ b/applications/desktop/scenes/desktop_scene_debug.c @@ -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); +} diff --git a/applications/desktop/scenes/desktop_scene_first_start.c b/applications/desktop/scenes/desktop_scene_first_start.c new file mode 100644 index 00000000..435947ca --- /dev/null +++ b/applications/desktop/scenes/desktop_scene_first_start.c @@ -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"); +} diff --git a/applications/desktop/scenes/desktop_scene_hw_mismatch.c b/applications/desktop/scenes/desktop_scene_hw_mismatch.c new file mode 100644 index 00000000..c01ed6ac --- /dev/null +++ b/applications/desktop/scenes/desktop_scene_hw_mismatch.c @@ -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; +} diff --git a/applications/desktop/scenes/desktop_scene_lock_menu.c b/applications/desktop/scenes/desktop_scene_lock_menu.c new file mode 100644 index 00000000..47ba850e --- /dev/null +++ b/applications/desktop/scenes/desktop_scene_lock_menu.c @@ -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); +} diff --git a/applications/desktop/scenes/desktop_scene_locked.c b/applications/desktop/scenes/desktop_scene_locked.c new file mode 100644 index 00000000..64a913c2 --- /dev/null +++ b/applications/desktop/scenes/desktop_scene_locked.c @@ -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); +} diff --git a/applications/desktop/scenes/desktop_scene_main.c b/applications/desktop/scenes/desktop_scene_main.c new file mode 100644 index 00000000..a9d7411f --- /dev/null +++ b/applications/desktop/scenes/desktop_scene_main.c @@ -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); +} diff --git a/applications/desktop/views/desktop_debug.c b/applications/desktop/views/desktop_debug.c new file mode 100644 index 00000000..00c70d9b --- /dev/null +++ b/applications/desktop/views/desktop_debug.c @@ -0,0 +1,166 @@ +#include +#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; + }); +} diff --git a/applications/desktop/views/desktop_debug.h b/applications/desktop/views/desktop_debug.h new file mode 100644 index 00000000..02ce76a2 --- /dev/null +++ b/applications/desktop/views/desktop_debug.h @@ -0,0 +1,52 @@ +#pragma once + +#include +#include +#include +#include +#include +#include + +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); \ No newline at end of file diff --git a/applications/desktop/views/desktop_first_start.c b/applications/desktop/views/desktop_first_start.c new file mode 100644 index 00000000..4c037f0b --- /dev/null +++ b/applications/desktop/views/desktop_first_start.c @@ -0,0 +1,107 @@ +#include +#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); +} diff --git a/applications/desktop/views/desktop_first_start.h b/applications/desktop/views/desktop_first_start.h new file mode 100644 index 00000000..4cc5b54a --- /dev/null +++ b/applications/desktop/views/desktop_first_start.h @@ -0,0 +1,35 @@ +#pragma once + +#include +#include +#include +#include +#include + +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); diff --git a/applications/desktop/views/desktop_hw_mismatch.c b/applications/desktop/views/desktop_hw_mismatch.c new file mode 100644 index 00000000..bf58d8f9 --- /dev/null +++ b/applications/desktop/views/desktop_hw_mismatch.c @@ -0,0 +1,66 @@ +#include +#include "../desktop_i.h" +#include +#include + +#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); +} diff --git a/applications/desktop/views/desktop_hw_mismatch.h b/applications/desktop/views/desktop_hw_mismatch.h new file mode 100644 index 00000000..68042341 --- /dev/null +++ b/applications/desktop/views/desktop_hw_mismatch.h @@ -0,0 +1,38 @@ +#pragma once + +#include +#include +#include +#include +#include + +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); diff --git a/applications/desktop/views/desktop_lock_menu.c b/applications/desktop/views/desktop_lock_menu.c new file mode 100644 index 00000000..5bb065d6 --- /dev/null +++ b/applications/desktop/views/desktop_lock_menu.c @@ -0,0 +1,111 @@ +#include +#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); +} diff --git a/applications/desktop/views/desktop_lock_menu.h b/applications/desktop/views/desktop_lock_menu.h new file mode 100644 index 00000000..d851bf91 --- /dev/null +++ b/applications/desktop/views/desktop_lock_menu.h @@ -0,0 +1,39 @@ +#pragma once + +#include +#include +#include +#include +#include + +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); diff --git a/applications/desktop/views/desktop_locked.c b/applications/desktop/views/desktop_locked.c new file mode 100644 index 00000000..80ec099c --- /dev/null +++ b/applications/desktop/views/desktop_locked.c @@ -0,0 +1,171 @@ +#include +#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); +} diff --git a/applications/desktop/views/desktop_locked.h b/applications/desktop/views/desktop_locked.h new file mode 100644 index 00000000..bf8db392 --- /dev/null +++ b/applications/desktop/views/desktop_locked.h @@ -0,0 +1,55 @@ +#pragma once + +#include +#include +#include +#include +#include + +#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); \ No newline at end of file diff --git a/applications/desktop/views/desktop_main.c b/applications/desktop/views/desktop_main.c new file mode 100644 index 00000000..171bb42e --- /dev/null +++ b/applications/desktop/views/desktop_main.c @@ -0,0 +1,116 @@ +#include +#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; + }); +} diff --git a/applications/desktop/views/desktop_main.h b/applications/desktop/views/desktop_main.h new file mode 100644 index 00000000..eadd1e82 --- /dev/null +++ b/applications/desktop/views/desktop_main.h @@ -0,0 +1,43 @@ +#pragma once + +#include +#include +#include +#include +#include + +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); diff --git a/applications/dolphin/dolphin.c b/applications/dolphin/dolphin.c index cdcef27e..a0d24df9 100644 --- a/applications/dolphin/dolphin.c +++ b/applications/dolphin/dolphin.c @@ -1,389 +1,9 @@ #include "dolphin_i.h" -#include -#include "applications.h" +#include -const Icon* idle_scenes[] = {&A_Wink_128x64, &A_WatchingTV_128x64}; - -static void dolphin_switch_to_app(Dolphin* dolphin, const FlipperApplication* flipper_app) { +bool dolphin_load(Dolphin* dolphin) { furi_assert(dolphin); - furi_assert(flipper_app); - 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); + return dolphin_state_load(dolphin->state); } 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); } -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(); - - 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); - if(!furi_hal_version_do_i_belong_here()) { - view_dispatcher_switch_to_view(dolphin->idle_view_dispatcher, DolphinViewHwMismatch); - } - DolphinEvent event; while(1) { furi_check(osMessageQueueGet(dolphin->event_queue, &event, NULL, osWaitForever) == osOK); - - DolphinViewLockMenuModel* lock_model = view_get_model(dolphin->view_lockmenu); - - 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) { + switch(event.type) { + case DolphinEventTypeDeed: dolphin_state_on_deed(dolphin->state, event.deed); - 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; - }); - } else if(event.type == DolphinEventTypeSave) { + break; + + case DolphinEventTypeSave: dolphin_state_save(dolphin->state); + break; + + default: + break; } } + dolphin_free(dolphin); return 0; } diff --git a/applications/dolphin/dolphin.h b/applications/dolphin/dolphin.h index 676f5dc5..0351417b 100644 --- a/applications/dolphin/dolphin.h +++ b/applications/dolphin/dolphin.h @@ -1,11 +1,30 @@ #pragma once -#include "dolphin_deed.h" +#include "helpers/dolphin_deed.h" typedef struct Dolphin Dolphin; +/* Load Dolphin state + * Thread safe + */ + +bool dolphin_load(Dolphin* dolphin); + /* Deed complete notification. Call it on deed completion. * See dolphin_deed.h for available deeds. In futures it will become part of assets. * Thread safe */ + 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); \ No newline at end of file diff --git a/applications/dolphin/dolphin_i.h b/applications/dolphin/dolphin_i.h index cd562492..f9393984 100644 --- a/applications/dolphin/dolphin_i.h +++ b/applications/dolphin/dolphin_i.h @@ -1,22 +1,10 @@ #pragma once -#include "dolphin.h" -#include "dolphin_state.h" -#include "dolphin_views.h" - #include #include -#include -#include -#include -#include -#include -#include - -#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) +#include "dolphin.h" +#include "helpers/dolphin_state.h" typedef enum { DolphinEventTypeDeed, @@ -32,36 +20,12 @@ typedef struct { } DolphinEvent; struct Dolphin { - // Internal message queue - osMessageQueueId_t event_queue; // State DolphinState* state; - // Menu - ValueMutex* menu_vm; - // 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; + // Queue + osMessageQueueId_t event_queue; }; Dolphin* dolphin_alloc(); void dolphin_free(Dolphin* dolphin); - -/* Save Dolphin state (write to permanent memory) - * Thread safe - */ -void dolphin_save(Dolphin* dolphin); diff --git a/applications/dolphin/dolphin_views.c b/applications/dolphin/dolphin_views.c deleted file mode 100644 index 953671e7..00000000 --- a/applications/dolphin/dolphin_views.c +++ /dev/null @@ -1,197 +0,0 @@ -#include "dolphin_views.h" -#include -#include -#include -#include -#include - -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; -} diff --git a/applications/dolphin/dolphin_views.h b/applications/dolphin/dolphin_views.h deleted file mode 100644 index 2f91b69a..00000000 --- a/applications/dolphin/dolphin_views.h +++ /dev/null @@ -1,67 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -// 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); diff --git a/applications/dolphin/dolphin_deed.c b/applications/dolphin/helpers/dolphin_deed.c similarity index 100% rename from applications/dolphin/dolphin_deed.c rename to applications/dolphin/helpers/dolphin_deed.c diff --git a/applications/dolphin/dolphin_deed.h b/applications/dolphin/helpers/dolphin_deed.h similarity index 91% rename from applications/dolphin/dolphin_deed.h rename to applications/dolphin/helpers/dolphin_deed.h index 2af1829a..afbf94c2 100644 --- a/applications/dolphin/dolphin_deed.h +++ b/applications/dolphin/helpers/dolphin_deed.h @@ -16,6 +16,7 @@ typedef enum { typedef struct { 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_interval; // interval, in minutes } DolphinDeedWeight; diff --git a/applications/dolphin/dolphin_state.c b/applications/dolphin/helpers/dolphin_state.c similarity index 100% rename from applications/dolphin/dolphin_state.c rename to applications/dolphin/helpers/dolphin_state.c diff --git a/applications/dolphin/dolphin_state.h b/applications/dolphin/helpers/dolphin_state.h similarity index 100% rename from applications/dolphin/dolphin_state.h rename to applications/dolphin/helpers/dolphin_state.h