diff --git a/README.md b/README.md
new file mode 100644
index 00000000000..b5693a0535e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,32 @@
+# Flipper Zero Color Guessing Game
+
+
+
+
+
+## What this is?
+As a web developer I enjoy guessing colours by HEX Code. This game is targeted at other Devs and graphic designers
+that also enjoy this.
+
+
+### Mode 1
+The LED will display a color and you must try and guess it by adjusting the HEX values on the screen. A timer will show
+how fast you were. Three levels of difficulty are available. Vibro hints given to help you find the solution.
+
+### Mode 2
+You can define a color using the HEX code on-screen and the LED will display this color
+
+
+## How to install on Flipper Zero
+- If you do not have one, download a firmware
+- Plug your Flipper Zero in via USB.
+- Copy the contents of this folder into the applications_user folder of your firmware.
+
+Then run the command:
+ ```
+.\fbt launch_app APPSRC=applications_user/color_guess
+ ```
+The application will be compiled and copied onto your device.
+
+## Licensing
+This code is open-source and may be used for whatever you want to do with it.
\ No newline at end of file
diff --git a/application.fam b/application.fam
new file mode 100644
index 00000000000..f24d51ce275
--- /dev/null
+++ b/application.fam
@@ -0,0 +1,19 @@
+App(
+ appid="color_guess",
+ name="Color Guess",
+ apptype=FlipperAppType.EXTERNAL,
+ entry_point="color_guess_app",
+ cdefines=["APP_COLOR_GUESS"],
+ requires=[
+ "gui",
+ ],
+ stack_size=2 * 1024,
+ order=10,
+ fap_icon="color_guess_10px.png",
+ fap_icon_assets="icons",
+ fap_version="1.1",
+ fap_category="Games",
+ fap_author="Leedave",
+ fap_description="Color Guessing Game",
+ fap_weburl="https://github.com/leedave/Leeds-Flipper-Zero-Applications",
+)
\ No newline at end of file
diff --git a/assets/flipper_logo_orange.png b/assets/flipper_logo_orange.png
new file mode 100644
index 00000000000..82148e819d0
Binary files /dev/null and b/assets/flipper_logo_orange.png differ
diff --git a/assets/preview.jpg b/assets/preview.jpg
new file mode 100644
index 00000000000..3bef5d4bd38
Binary files /dev/null and b/assets/preview.jpg differ
diff --git a/changelog.md b/changelog.md
new file mode 100644
index 00000000000..c4d4c1b0ad2
--- /dev/null
+++ b/changelog.md
@@ -0,0 +1,7 @@
+## v1.1
+
+Added GFX to start screen
+
+## v1.0
+
+First release to Application Catalog
\ No newline at end of file
diff --git a/color_guess.c b/color_guess.c
new file mode 100644
index 00000000000..90c387c36b2
--- /dev/null
+++ b/color_guess.c
@@ -0,0 +1,137 @@
+#include "color_guess.h"
+#include "helpers/digits.h"
+
+bool color_guess_custom_event_callback(void* context, uint32_t event) {
+ furi_assert(context);
+ ColorGuess* app = context;
+ return scene_manager_handle_custom_event(app->scene_manager, event);
+}
+
+void color_guess_tick_event_callback(void* context) {
+ furi_assert(context);
+ ColorGuess* app = context;
+ scene_manager_handle_tick_event(app->scene_manager);
+}
+
+//leave app if back button pressed
+bool color_guess_navigation_event_callback(void* context) {
+ furi_assert(context);
+ ColorGuess* app = context;
+ return scene_manager_handle_back_event(app->scene_manager);
+}
+
+ColorGuess* color_guess_app_alloc() {
+ ColorGuess* app = malloc(sizeof(ColorGuess));
+ app->gui = furi_record_open(RECORD_GUI);
+ app->notification = furi_record_open(RECORD_NOTIFICATION);
+ app->error = false;
+
+ // Set Defaults if no config exists
+ app->haptic = 1;
+ app->led = 1;
+ app->save_settings = 1;
+
+ // Load configs
+ color_guess_read_settings(app);
+
+ NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
+ notification_message(notification, &sequence_display_backlight_on);
+
+ //Scene additions
+ app->view_dispatcher = view_dispatcher_alloc();
+ view_dispatcher_enable_queue(app->view_dispatcher);
+
+ app->scene_manager = scene_manager_alloc(&color_guess_scene_handlers, app);
+ view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
+ view_dispatcher_set_navigation_event_callback(
+ app->view_dispatcher, color_guess_navigation_event_callback);
+ view_dispatcher_set_tick_event_callback(
+ app->view_dispatcher, color_guess_tick_event_callback, 100);
+ view_dispatcher_set_custom_event_callback(
+ app->view_dispatcher, color_guess_custom_event_callback);
+ app->submenu = submenu_alloc();
+
+ view_dispatcher_add_view(
+ app->view_dispatcher, ColorGuessViewIdMenu, submenu_get_view(app->submenu));
+ app->variable_item_list = variable_item_list_alloc();
+ view_dispatcher_add_view(
+ app->view_dispatcher,
+ ColorGuessViewIdSettings,
+ variable_item_list_get_view(app->variable_item_list));
+ app->color_guess_startscreen = color_guess_startscreen_alloc();
+ view_dispatcher_add_view(
+ app->view_dispatcher,
+ ColorGuessViewIdStartscreen,
+ color_guess_startscreen_get_view(app->color_guess_startscreen));
+ app->color_guess_color_set = color_guess_color_set_alloc();
+ view_dispatcher_add_view(
+ app->view_dispatcher,
+ ColorGuessViewIdColorSet,
+ color_guess_color_set_get_view(app->color_guess_color_set));
+ app->color_guess_play = color_guess_play_alloc();
+ view_dispatcher_add_view(
+ app->view_dispatcher,
+ ColorGuessViewIdPlay,
+ color_guess_play_get_view(app->color_guess_play));
+
+ //End Scene Additions
+
+ return app;
+}
+
+void color_guess_app_free(ColorGuess* app) {
+ furi_assert(app);
+
+ // Scene manager
+ scene_manager_free(app->scene_manager);
+
+ // View Dispatcher
+ view_dispatcher_remove_view(app->view_dispatcher, ColorGuessViewIdMenu);
+ view_dispatcher_remove_view(app->view_dispatcher, ColorGuessViewIdStartscreen);
+ view_dispatcher_remove_view(app->view_dispatcher, ColorGuessViewIdColorSet);
+ view_dispatcher_remove_view(app->view_dispatcher, ColorGuessViewIdPlay);
+ view_dispatcher_remove_view(app->view_dispatcher, ColorGuessViewIdSettings);
+ submenu_free(app->submenu);
+
+ view_dispatcher_free(app->view_dispatcher);
+
+ // GUI
+ furi_record_close(RECORD_GUI);
+
+ app->view_port = NULL;
+ app->gui = NULL;
+ app->notification = NULL;
+
+ //Remove whatever is left
+ free(app);
+}
+
+int32_t color_guess_app(void* p) {
+ UNUSED(p);
+ ColorGuess* app = color_guess_app_alloc();
+ if(app->error) {
+ return 255;
+ }
+
+ /* //This exits if run in RM FW
+ if(!furi_hal_region_is_provisioned()) {
+ color_guess_app_free(app);
+ return 1;
+ }*/
+
+ view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
+
+ scene_manager_next_scene(app->scene_manager, ColorGuessSceneStartscreen);
+
+ furi_hal_power_suppress_charge_enter();
+
+ view_dispatcher_run(app->view_dispatcher);
+
+ color_guess_save_settings(app);
+
+ furi_hal_power_suppress_charge_exit();
+
+ color_guess_app_free(app);
+
+ return 0;
+}
diff --git a/color_guess.h b/color_guess.h
new file mode 100644
index 00000000000..a6c1dac4580
--- /dev/null
+++ b/color_guess.h
@@ -0,0 +1,62 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include "helpers/color_guess_custom_event.h"
+#include "scenes/color_guess_scene.h"
+#include "views/color_guess_color_set.h"
+#include "views/color_guess_play.h"
+#include "views/color_guess_startscreen.h"
+#include "helpers/color_guess_storage.h"
+
+#define TAG "Color_Guess"
+
+typedef struct {
+ Gui* gui;
+ NotificationApp* notification;
+ ViewPort* view_port;
+ ViewDispatcher* view_dispatcher;
+ Submenu* submenu;
+ VariableItemList* variable_item_list;
+ SceneManager* scene_manager;
+ ColorGuessColorSet* color_guess_color_set;
+ ColorGuessPlay* color_guess_play;
+ ColorGuessStartscreen* color_guess_startscreen;
+ Submenu* color_guess_settings;
+ bool error;
+ uint32_t haptic;
+ //uint32_t speaker;
+ uint32_t led;
+ uint32_t save_settings;
+} ColorGuess;
+
+typedef enum {
+ ColorGuessViewIdStartscreen,
+ ColorGuessViewIdMenu,
+ ColorGuessViewIdPlay,
+ ColorGuessViewIdColorSet,
+ ColorGuessViewIdSettings,
+} ColorGuessViewId;
+
+typedef enum {
+ ColorGuessHapticOff,
+ ColorGuessHapticOn,
+} ColorGuessHapticState;
+
+typedef enum {
+ ColorGuessSpeakerOff,
+ ColorGuessSpeakerOn,
+} ColorGuessSpeakerState;
+
+typedef enum {
+ ColorGuessLedOff,
+ ColorGuessLedOn,
+} ColorGuessLedState;
\ No newline at end of file
diff --git a/color_guess_10px.png b/color_guess_10px.png
new file mode 100644
index 00000000000..207c2921ee5
Binary files /dev/null and b/color_guess_10px.png differ
diff --git a/docs/README.md b/docs/README.md
new file mode 100644
index 00000000000..e87feb0fba3
--- /dev/null
+++ b/docs/README.md
@@ -0,0 +1,20 @@
+## Color Guessing Game
+
+Targeted at Web Developers, Graphical Designers and other nerds.
+This app will let your devices LED glow in a random color. Your job is to guess the Hex Code of the color.
+
+## Features
+- 3 Difficulties
+- Optional haptic feedback helps you guess
+- Percentage calculation to show how close you are
+- Practice mode that lets you define colors yourself
+
+## How HEX color codes work
+
+Example #FF44CC
+- Each digit is a number from 0 - F
+- One digit represents 0 - 15, two digits represent 0 - 255
+- Each colors intensity is defined by two digits (black to full color)
+- The first color is red (example: FF)
+- The second color is green (example: 44)
+- The third color is blue (example: CC)
\ No newline at end of file
diff --git a/docs/changelog.md b/docs/changelog.md
new file mode 100644
index 00000000000..5cc5cd98c06
--- /dev/null
+++ b/docs/changelog.md
@@ -0,0 +1,3 @@
+## v1.0
+
+First release to Application Catalog
\ No newline at end of file
diff --git a/helpers/color_guess_colors.h b/helpers/color_guess_colors.h
new file mode 100644
index 00000000000..7d852db01e9
--- /dev/null
+++ b/helpers/color_guess_colors.h
@@ -0,0 +1,21 @@
+#pragma once
+
+int colorsEasy[] = {
+ 0xff0000, 0x00ff00, 0x0000ff, 0xffff00, 0xff00ff, 0x00ffff, 0xffffff, 0x500000,
+ 0x005000, 0x000050, 0x505000, 0x500050, 0x005050, 0x505050, 0x0000c0, 0x010101,
+ 0xcccccc, 0xcc00cc, 0x00cccc, 0xcccc00, 0xcc0000, 0x00cc00, 0x0000cc, 0x000000,
+};
+
+int colorsNormal[] = {
+ 0xa04a00, 0x308030, 0xc03030, 0x00e090, 0x0000ad, 0xaf00af, 0xbb3030, 0xcccc00,
+ 0xcc8000, 0x0080f0, 0x009020, 0x902050, 0xbc00ff, 0xff6a00, 0xc5c5c5, 0xafafc0,
+ 0xcece00, 0xcf6500, 0x2b2b00, 0x55ee11, 0xff33ff, 0x2266ff, 0x530053, 0x3399ff,
+ 0xff0033, 0x99ff22, 0xab00ab, 0x55ff55, 0x9999ff, 0xe500e5,
+};
+
+int colorsHard[] = {
+ 0x94275d, 0xb4f73e, 0xc833fd, 0x813f00, 0xb77b51, 0xe2b739, 0x378b3a, 0x373e8b, 0x8b3785,
+ 0x8b4137, 0xffbdb5, 0x3a3aa7, 0x37a6bd, 0xbd4737, 0x621308, 0x086238, 0x2d4137, 0x711761,
+ 0xdc26bc, 0xdc266e, 0x26dc81, 0x8d4500, 0xb8c22b, 0x2bc2a0, 0x9064c1, 0x732bc2, 0x5610a3,
+ 0xa31034, 0xe50c41, 0x6d001a, 0x159bbc, 0x32bc15, 0x53e60c,
+};
\ No newline at end of file
diff --git a/helpers/color_guess_custom_event.h b/helpers/color_guess_custom_event.h
new file mode 100644
index 00000000000..90e75947996
--- /dev/null
+++ b/helpers/color_guess_custom_event.h
@@ -0,0 +1,22 @@
+#pragma once
+
+typedef enum {
+ ColorGuessCustomEventStartscreenUp,
+ ColorGuessCustomEventStartscreenDown,
+ ColorGuessCustomEventStartscreenLeft,
+ ColorGuessCustomEventStartscreenRight,
+ ColorGuessCustomEventStartscreenOk,
+ ColorGuessCustomEventStartscreenBack,
+ ColorGuessCustomEventColorSetUp,
+ ColorGuessCustomEventColorSetDown,
+ ColorGuessCustomEventColorSetLeft,
+ ColorGuessCustomEventColorSetRight,
+ ColorGuessCustomEventColorSetOk,
+ ColorGuessCustomEventColorSetBack,
+ ColorGuessCustomEventPlayUp,
+ ColorGuessCustomEventPlayDown,
+ ColorGuessCustomEventPlayLeft,
+ ColorGuessCustomEventPlayRight,
+ ColorGuessCustomEventPlayOk,
+ ColorGuessCustomEventPlayBack,
+} ColorGuessCustomEvent;
\ No newline at end of file
diff --git a/helpers/color_guess_haptic.c b/helpers/color_guess_haptic.c
new file mode 100644
index 00000000000..231f8afed90
--- /dev/null
+++ b/helpers/color_guess_haptic.c
@@ -0,0 +1,35 @@
+#include "color_guess_haptic.h"
+#include "../color_guess.h"
+
+void color_guess_play_happy_bump(void* context) {
+ ColorGuess* app = context;
+ if(app->haptic != 1) {
+ return;
+ }
+ notification_message(app->notification, &sequence_set_vibro_on);
+ furi_thread_flags_wait(0, FuriFlagWaitAny, 20);
+ notification_message(app->notification, &sequence_reset_vibro);
+}
+
+void color_guess_play_bad_bump(void* context) {
+ ColorGuess* app = context;
+ if(app->haptic != 1) {
+ return;
+ }
+ notification_message(app->notification, &sequence_set_vibro_on);
+ furi_thread_flags_wait(0, FuriFlagWaitAny, 100);
+ notification_message(app->notification, &sequence_reset_vibro);
+}
+
+void color_guess_play_long_bump(void* context) {
+ ColorGuess* app = context;
+ if(app->haptic != 1) {
+ return;
+ }
+ for(int i = 0; i < 4; i++) {
+ notification_message(app->notification, &sequence_set_vibro_on);
+ furi_thread_flags_wait(0, FuriFlagWaitAny, 50);
+ notification_message(app->notification, &sequence_reset_vibro);
+ furi_thread_flags_wait(0, FuriFlagWaitAny, 100);
+ }
+}
diff --git a/helpers/color_guess_haptic.h b/helpers/color_guess_haptic.h
new file mode 100644
index 00000000000..15862034559
--- /dev/null
+++ b/helpers/color_guess_haptic.h
@@ -0,0 +1,9 @@
+#pragma once
+
+#include
+
+void color_guess_play_happy_bump(void* context);
+
+void color_guess_play_bad_bump(void* context);
+
+void color_guess_play_long_bump(void* context);
diff --git a/helpers/color_guess_led.c b/helpers/color_guess_led.c
new file mode 100644
index 00000000000..46d58e0a24d
--- /dev/null
+++ b/helpers/color_guess_led.c
@@ -0,0 +1,39 @@
+#include "color_guess_led.h"
+#include "../color_guess.h"
+
+void color_guess_led_set_rgb(void* context, int red, int green, int blue) {
+ ColorGuess* app = context;
+ if(app->led != 1) {
+ return;
+ }
+ NotificationMessage notification_led_message_1;
+ notification_led_message_1.type = NotificationMessageTypeLedRed;
+ NotificationMessage notification_led_message_2;
+ notification_led_message_2.type = NotificationMessageTypeLedGreen;
+ NotificationMessage notification_led_message_3;
+ notification_led_message_3.type = NotificationMessageTypeLedBlue;
+
+ notification_led_message_1.data.led.value = red;
+ notification_led_message_2.data.led.value = green;
+ notification_led_message_3.data.led.value = blue;
+ const NotificationSequence notification_sequence = {
+ ¬ification_led_message_1,
+ ¬ification_led_message_2,
+ ¬ification_led_message_3,
+ &message_do_not_reset,
+ NULL,
+ };
+ notification_message(app->notification, ¬ification_sequence);
+ furi_thread_flags_wait(
+ 0, FuriFlagWaitAny, 10); //Delay, prevent removal from RAM before LED value set
+}
+
+void color_guess_led_reset(void* context) {
+ ColorGuess* app = context;
+ notification_message(app->notification, &sequence_reset_red);
+ notification_message(app->notification, &sequence_reset_green);
+ notification_message(app->notification, &sequence_reset_blue);
+
+ furi_thread_flags_wait(
+ 0, FuriFlagWaitAny, 300); //Delay, prevent removal from RAM before LED value set
+}
diff --git a/helpers/color_guess_led.h b/helpers/color_guess_led.h
new file mode 100644
index 00000000000..513a67e39f4
--- /dev/null
+++ b/helpers/color_guess_led.h
@@ -0,0 +1,5 @@
+#pragma once
+
+void color_guess_led_set_rgb(void* context, int red, int green, int blue);
+
+void color_guess_led_reset(void* context);
diff --git a/helpers/color_guess_storage.c b/helpers/color_guess_storage.c
new file mode 100644
index 00000000000..71432599212
--- /dev/null
+++ b/helpers/color_guess_storage.c
@@ -0,0 +1,114 @@
+#include "color_guess_storage.h"
+
+static Storage* color_guess_open_storage() {
+ return furi_record_open(RECORD_STORAGE);
+}
+
+static void color_guess_close_storage() {
+ furi_record_close(RECORD_STORAGE);
+}
+
+static void color_guess_close_config_file(FlipperFormat* file) {
+ if(file == NULL) return;
+ flipper_format_file_close(file);
+ flipper_format_free(file);
+}
+
+void color_guess_save_settings(void* context) {
+ ColorGuess* app = context;
+ if(app->save_settings == 0) {
+ return;
+ }
+
+ FURI_LOG_D(TAG, "Saving Settings");
+ Storage* storage = color_guess_open_storage();
+ FlipperFormat* fff_file = flipper_format_file_alloc(storage);
+
+ // Overwrite wont work, so delete first
+ if(storage_file_exists(storage, COLOR_GUESS_SETTINGS_SAVE_PATH)) {
+ storage_simply_remove(storage, COLOR_GUESS_SETTINGS_SAVE_PATH);
+ }
+
+ // Open File, create if not exists
+ if(!storage_common_stat(storage, COLOR_GUESS_SETTINGS_SAVE_PATH, NULL) == FSE_OK) {
+ FURI_LOG_D(
+ TAG, "Config file %s is not found. Will create new.", COLOR_GUESS_SETTINGS_SAVE_PATH);
+ if(storage_common_stat(storage, CONFIG_FILE_DIRECTORY_PATH, NULL) == FSE_NOT_EXIST) {
+ FURI_LOG_D(
+ TAG, "Directory %s doesn't exist. Will create new.", CONFIG_FILE_DIRECTORY_PATH);
+ if(!storage_simply_mkdir(storage, CONFIG_FILE_DIRECTORY_PATH)) {
+ FURI_LOG_E(TAG, "Error creating directory %s", CONFIG_FILE_DIRECTORY_PATH);
+ }
+ }
+ }
+
+ if(!flipper_format_file_open_new(fff_file, COLOR_GUESS_SETTINGS_SAVE_PATH)) {
+ //totp_close_config_file(fff_file);
+ FURI_LOG_E(TAG, "Error creating new file %s", COLOR_GUESS_SETTINGS_SAVE_PATH);
+ color_guess_close_storage();
+ return;
+ }
+
+ // Store Settings
+ flipper_format_write_header_cstr(
+ fff_file, COLOR_GUESS_SETTINGS_HEADER, COLOR_GUESS_SETTINGS_FILE_VERSION);
+ flipper_format_write_uint32(fff_file, COLOR_GUESS_SETTINGS_KEY_HAPTIC, &app->haptic, 1);
+ flipper_format_write_uint32(fff_file, COLOR_GUESS_SETTINGS_KEY_LED, &app->led, 1);
+ flipper_format_write_uint32(
+ fff_file, COLOR_GUESS_SETTINGS_KEY_SAVE_SETTINGS, &app->save_settings, 1);
+
+ if(!flipper_format_rewind(fff_file)) {
+ color_guess_close_config_file(fff_file);
+ FURI_LOG_E(TAG, "Rewind error");
+ color_guess_close_storage();
+ return;
+ }
+
+ color_guess_close_config_file(fff_file);
+ color_guess_close_storage();
+}
+
+void color_guess_read_settings(void* context) {
+ ColorGuess* app = context;
+ Storage* storage = color_guess_open_storage();
+ FlipperFormat* fff_file = flipper_format_file_alloc(storage);
+
+ if(storage_common_stat(storage, COLOR_GUESS_SETTINGS_SAVE_PATH, NULL) != FSE_OK) {
+ color_guess_close_config_file(fff_file);
+ color_guess_close_storage();
+ return;
+ }
+ uint32_t file_version;
+ FuriString* temp_str = furi_string_alloc();
+
+ if(!flipper_format_file_open_existing(fff_file, COLOR_GUESS_SETTINGS_SAVE_PATH)) {
+ FURI_LOG_E(TAG, "Cannot open file %s", COLOR_GUESS_SETTINGS_SAVE_PATH);
+ color_guess_close_config_file(fff_file);
+ color_guess_close_storage();
+ return;
+ }
+
+ if(!flipper_format_read_header(fff_file, temp_str, &file_version)) {
+ FURI_LOG_E(TAG, "Missing Header Data");
+ color_guess_close_config_file(fff_file);
+ color_guess_close_storage();
+ return;
+ }
+
+ if(file_version < COLOR_GUESS_SETTINGS_FILE_VERSION) {
+ FURI_LOG_I(TAG, "old config version, will be removed.");
+ color_guess_close_config_file(fff_file);
+ color_guess_close_storage();
+ return;
+ }
+
+ flipper_format_read_uint32(fff_file, COLOR_GUESS_SETTINGS_KEY_HAPTIC, &app->haptic, 1);
+ flipper_format_read_uint32(fff_file, COLOR_GUESS_SETTINGS_KEY_LED, &app->led, 1);
+ flipper_format_read_uint32(
+ fff_file, COLOR_GUESS_SETTINGS_KEY_SAVE_SETTINGS, &app->save_settings, 1);
+
+ flipper_format_rewind(fff_file);
+
+ color_guess_close_config_file(fff_file);
+ color_guess_close_storage();
+}
\ No newline at end of file
diff --git a/helpers/color_guess_storage.h b/helpers/color_guess_storage.h
new file mode 100644
index 00000000000..305d13db184
--- /dev/null
+++ b/helpers/color_guess_storage.h
@@ -0,0 +1,20 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+#include "../color_guess.h"
+
+#define COLOR_GUESS_SETTINGS_FILE_VERSION 1
+#define CONFIG_FILE_DIRECTORY_PATH EXT_PATH("apps_data/color_guess")
+#define COLOR_GUESS_SETTINGS_SAVE_PATH CONFIG_FILE_DIRECTORY_PATH "/color_guess.conf"
+#define COLOR_GUESS_SETTINGS_SAVE_PATH_TMP COLOR_GUESS_SETTINGS_SAVE_PATH ".tmp"
+#define COLOR_GUESS_SETTINGS_HEADER "Color Guess Config File"
+#define COLOR_GUESS_SETTINGS_KEY_HAPTIC "Haptic"
+#define COLOR_GUESS_SETTINGS_KEY_LED "Led"
+#define COLOR_GUESS_SETTINGS_KEY_SPEAKER "Speaker"
+#define COLOR_GUESS_SETTINGS_KEY_SAVE_SETTINGS "SaveSettings"
+
+void color_guess_save_settings(void* context);
+void color_guess_read_settings(void* context);
\ No newline at end of file
diff --git a/helpers/digits.h b/helpers/digits.h
new file mode 100644
index 00000000000..b4144d11c6f
--- /dev/null
+++ b/helpers/digits.h
@@ -0,0 +1,23 @@
+//#pragma once
+
+#include
+#include "color_guess_icons.h"
+
+const Icon* digits[17] = {
+ &I_digit_0_10x14,
+ &I_digit_1_10x14,
+ &I_digit_2_10x14,
+ &I_digit_3_10x14,
+ &I_digit_4_10x14,
+ &I_digit_5_10x14,
+ &I_digit_6_10x14,
+ &I_digit_7_10x14,
+ &I_digit_8_10x14,
+ &I_digit_9_10x14,
+ &I_digit_a_10x14,
+ &I_digit_b_10x14,
+ &I_digit_c_10x14,
+ &I_digit_d_10x14,
+ &I_digit_e_10x14,
+ &I_digit_f_10x14,
+ &I_digit_x_10x14};
diff --git a/icons/ButtonCenter_7x7.png b/icons/ButtonCenter_7x7.png
new file mode 100644
index 00000000000..a66461b227b
Binary files /dev/null and b/icons/ButtonCenter_7x7.png differ
diff --git a/icons/ButtonDown_10x5.png b/icons/ButtonDown_10x5.png
new file mode 100644
index 00000000000..b492b926c45
Binary files /dev/null and b/icons/ButtonDown_10x5.png differ
diff --git a/icons/ButtonUp_10x5.png b/icons/ButtonUp_10x5.png
new file mode 100644
index 00000000000..5da99d01ee9
Binary files /dev/null and b/icons/ButtonUp_10x5.png differ
diff --git a/icons/digit_0_10x14.png b/icons/digit_0_10x14.png
new file mode 100644
index 00000000000..a874b194034
Binary files /dev/null and b/icons/digit_0_10x14.png differ
diff --git a/icons/digit_1_10x14.png b/icons/digit_1_10x14.png
new file mode 100644
index 00000000000..2f18aaa9bd2
Binary files /dev/null and b/icons/digit_1_10x14.png differ
diff --git a/icons/digit_2_10x14.png b/icons/digit_2_10x14.png
new file mode 100644
index 00000000000..05e72d69305
Binary files /dev/null and b/icons/digit_2_10x14.png differ
diff --git a/icons/digit_3_10x14.png b/icons/digit_3_10x14.png
new file mode 100644
index 00000000000..f791ae25bea
Binary files /dev/null and b/icons/digit_3_10x14.png differ
diff --git a/icons/digit_4_10x14.png b/icons/digit_4_10x14.png
new file mode 100644
index 00000000000..ab98aa77f25
Binary files /dev/null and b/icons/digit_4_10x14.png differ
diff --git a/icons/digit_5_10x14.png b/icons/digit_5_10x14.png
new file mode 100644
index 00000000000..4305f46dd2a
Binary files /dev/null and b/icons/digit_5_10x14.png differ
diff --git a/icons/digit_6_10x14.png b/icons/digit_6_10x14.png
new file mode 100644
index 00000000000..b170f29a77d
Binary files /dev/null and b/icons/digit_6_10x14.png differ
diff --git a/icons/digit_7_10x14.png b/icons/digit_7_10x14.png
new file mode 100644
index 00000000000..9f38be8376e
Binary files /dev/null and b/icons/digit_7_10x14.png differ
diff --git a/icons/digit_8_10x14.png b/icons/digit_8_10x14.png
new file mode 100644
index 00000000000..464f9229350
Binary files /dev/null and b/icons/digit_8_10x14.png differ
diff --git a/icons/digit_9_10x14.png b/icons/digit_9_10x14.png
new file mode 100644
index 00000000000..13f1563089e
Binary files /dev/null and b/icons/digit_9_10x14.png differ
diff --git a/icons/digit_a_10x14.png b/icons/digit_a_10x14.png
new file mode 100644
index 00000000000..5359cc453e7
Binary files /dev/null and b/icons/digit_a_10x14.png differ
diff --git a/icons/digit_b_10x14.png b/icons/digit_b_10x14.png
new file mode 100644
index 00000000000..502da3d4e36
Binary files /dev/null and b/icons/digit_b_10x14.png differ
diff --git a/icons/digit_c_10x14.png b/icons/digit_c_10x14.png
new file mode 100644
index 00000000000..a5c35eff9a3
Binary files /dev/null and b/icons/digit_c_10x14.png differ
diff --git a/icons/digit_d_10x14.png b/icons/digit_d_10x14.png
new file mode 100644
index 00000000000..e149214b968
Binary files /dev/null and b/icons/digit_d_10x14.png differ
diff --git a/icons/digit_e_10x14.png b/icons/digit_e_10x14.png
new file mode 100644
index 00000000000..88e31f2f400
Binary files /dev/null and b/icons/digit_e_10x14.png differ
diff --git a/icons/digit_f_10x14.png b/icons/digit_f_10x14.png
new file mode 100644
index 00000000000..a5088380388
Binary files /dev/null and b/icons/digit_f_10x14.png differ
diff --git a/icons/digit_x_10x14.png b/icons/digit_x_10x14.png
new file mode 100644
index 00000000000..8d45ea022ac
Binary files /dev/null and b/icons/digit_x_10x14.png differ
diff --git a/icons/start_dolph_49x55.png b/icons/start_dolph_49x55.png
new file mode 100644
index 00000000000..89a29a33384
Binary files /dev/null and b/icons/start_dolph_49x55.png differ
diff --git a/scenes/color_guess_scene.c b/scenes/color_guess_scene.c
new file mode 100644
index 00000000000..14745a10e81
--- /dev/null
+++ b/scenes/color_guess_scene.c
@@ -0,0 +1,30 @@
+#include "color_guess_scene.h"
+
+// Generate scene on_enter handlers array
+#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
+void (*const color_guess_on_enter_handlers[])(void*) = {
+#include "color_guess_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 color_guess_on_event_handlers[])(void* context, SceneManagerEvent event) = {
+#include "color_guess_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 color_guess_on_exit_handlers[])(void* context) = {
+#include "color_guess_scene_config.h"
+};
+#undef ADD_SCENE
+
+// Initialize scene handlers configuration structure
+const SceneManagerHandlers color_guess_scene_handlers = {
+ .on_enter_handlers = color_guess_on_enter_handlers,
+ .on_event_handlers = color_guess_on_event_handlers,
+ .on_exit_handlers = color_guess_on_exit_handlers,
+ .scene_num = ColorGuessSceneNum,
+};
diff --git a/scenes/color_guess_scene.h b/scenes/color_guess_scene.h
new file mode 100644
index 00000000000..aaa07b1a24b
--- /dev/null
+++ b/scenes/color_guess_scene.h
@@ -0,0 +1,29 @@
+#pragma once
+
+#include
+
+// Generate scene id and total number
+#define ADD_SCENE(prefix, name, id) ColorGuessScene##id,
+typedef enum {
+#include "color_guess_scene_config.h"
+ ColorGuessSceneNum,
+} ColorGuessScene;
+#undef ADD_SCENE
+
+extern const SceneManagerHandlers color_guess_scene_handlers;
+
+// Generate scene on_enter handlers declaration
+#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
+#include "color_guess_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 "color_guess_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 "color_guess_scene_config.h"
+#undef ADD_SCENE
diff --git a/scenes/color_guess_scene_color_set.c b/scenes/color_guess_scene_color_set.c
new file mode 100644
index 00000000000..3c478c30a56
--- /dev/null
+++ b/scenes/color_guess_scene_color_set.c
@@ -0,0 +1,51 @@
+#include "../color_guess.h"
+#include "../helpers/color_guess_custom_event.h"
+#include "../views/color_guess_color_set.h"
+
+void color_guess_color_set_callback(ColorGuessCustomEvent event, void* context) {
+ furi_assert(context);
+ ColorGuess* app = context;
+ view_dispatcher_send_custom_event(app->view_dispatcher, event);
+}
+
+void color_guess_scene_color_set_on_enter(void* context) {
+ furi_assert(context);
+ ColorGuess* app = context;
+ color_guess_color_set_set_callback(
+ app->color_guess_color_set, color_guess_color_set_callback, app);
+ view_dispatcher_switch_to_view(app->view_dispatcher, ColorGuessViewIdColorSet);
+}
+
+bool color_guess_scene_color_set_on_event(void* context, SceneManagerEvent event) {
+ ColorGuess* app = context;
+ bool consumed = false;
+
+ if(event.type == SceneManagerEventTypeCustom) {
+ switch(event.event) {
+ case ColorGuessCustomEventColorSetLeft:
+ case ColorGuessCustomEventColorSetRight:
+ break;
+ case ColorGuessCustomEventColorSetUp:
+ case ColorGuessCustomEventColorSetDown:
+ break;
+ case ColorGuessCustomEventColorSetBack:
+ notification_message(app->notification, &sequence_reset_red);
+ notification_message(app->notification, &sequence_reset_green);
+ notification_message(app->notification, &sequence_reset_blue);
+ if(!scene_manager_search_and_switch_to_previous_scene(
+ app->scene_manager, ColorGuessSceneMenu)) {
+ scene_manager_stop(app->scene_manager);
+ view_dispatcher_stop(app->view_dispatcher);
+ }
+ consumed = true;
+ break;
+ }
+ }
+
+ return consumed;
+}
+
+void color_guess_scene_color_set_on_exit(void* context) {
+ ColorGuess* app = context;
+ UNUSED(app);
+}
diff --git a/scenes/color_guess_scene_config.h b/scenes/color_guess_scene_config.h
new file mode 100644
index 00000000000..5efe884134d
--- /dev/null
+++ b/scenes/color_guess_scene_config.h
@@ -0,0 +1,5 @@
+ADD_SCENE(color_guess, startscreen, Startscreen)
+ADD_SCENE(color_guess, menu, Menu)
+ADD_SCENE(color_guess, color_set, ColorSet)
+ADD_SCENE(color_guess, play, Play)
+ADD_SCENE(color_guess, settings, Settings)
\ No newline at end of file
diff --git a/scenes/color_guess_scene_menu.c b/scenes/color_guess_scene_menu.c
new file mode 100644
index 00000000000..8a47527a977
--- /dev/null
+++ b/scenes/color_guess_scene_menu.c
@@ -0,0 +1,69 @@
+#include "../color_guess.h"
+
+enum SubmenuIndex {
+ SubmenuIndexPlay = 10,
+ SubmenuIndexColorSet,
+ SubmenuIndexSettings,
+};
+
+void color_guess_scene_menu_submenu_callback(void* context, uint32_t index) {
+ ColorGuess* app = context;
+ view_dispatcher_send_custom_event(app->view_dispatcher, index);
+}
+
+void color_guess_scene_menu_on_enter(void* context) {
+ ColorGuess* app = context;
+
+ submenu_add_item(
+ app->submenu, "Play Game", SubmenuIndexPlay, color_guess_scene_menu_submenu_callback, app);
+ submenu_add_item(
+ app->submenu,
+ "Set Color",
+ SubmenuIndexColorSet,
+ color_guess_scene_menu_submenu_callback,
+ app);
+ submenu_add_item(
+ app->submenu,
+ "Settings",
+ SubmenuIndexSettings,
+ color_guess_scene_menu_submenu_callback,
+ app);
+
+ submenu_set_selected_item(
+ app->submenu, scene_manager_get_scene_state(app->scene_manager, ColorGuessSceneMenu));
+ view_dispatcher_switch_to_view(app->view_dispatcher, ColorGuessViewIdMenu);
+}
+
+bool color_guess_scene_menu_on_event(void* context, SceneManagerEvent event) {
+ ColorGuess* app = context;
+ UNUSED(app);
+ if(event.type == SceneManagerEventTypeBack) {
+ //exit app
+ scene_manager_stop(app->scene_manager);
+ view_dispatcher_stop(app->view_dispatcher);
+ return true;
+ } else if(event.type == SceneManagerEventTypeCustom) {
+ if(event.event == SubmenuIndexColorSet) {
+ scene_manager_set_scene_state(
+ app->scene_manager, ColorGuessSceneMenu, SubmenuIndexColorSet);
+ scene_manager_next_scene(app->scene_manager, ColorGuessSceneColorSet);
+ return true;
+ } else if(event.event == SubmenuIndexPlay) {
+ scene_manager_set_scene_state(
+ app->scene_manager, ColorGuessSceneMenu, SubmenuIndexPlay);
+ scene_manager_next_scene(app->scene_manager, ColorGuessScenePlay);
+ return true;
+ } else if(event.event == SubmenuIndexSettings) {
+ scene_manager_set_scene_state(
+ app->scene_manager, ColorGuessSceneMenu, SubmenuIndexSettings);
+ scene_manager_next_scene(app->scene_manager, ColorGuessSceneSettings);
+ return true;
+ }
+ }
+ return false;
+}
+
+void color_guess_scene_menu_on_exit(void* context) {
+ ColorGuess* app = context;
+ submenu_reset(app->submenu);
+}
\ No newline at end of file
diff --git a/scenes/color_guess_scene_play.c b/scenes/color_guess_scene_play.c
new file mode 100644
index 00000000000..f45c5c1d7c7
--- /dev/null
+++ b/scenes/color_guess_scene_play.c
@@ -0,0 +1,50 @@
+#include "../color_guess.h"
+#include "../helpers/color_guess_custom_event.h"
+#include "../views/color_guess_play.h"
+
+void color_guess_play_callback(ColorGuessCustomEvent event, void* context) {
+ furi_assert(context);
+ ColorGuess* app = context;
+ view_dispatcher_send_custom_event(app->view_dispatcher, event);
+}
+
+void color_guess_scene_play_on_enter(void* context) {
+ furi_assert(context);
+ ColorGuess* app = context;
+ color_guess_play_set_callback(app->color_guess_play, color_guess_play_callback, app);
+ view_dispatcher_switch_to_view(app->view_dispatcher, ColorGuessViewIdPlay);
+}
+
+bool color_guess_scene_play_on_event(void* context, SceneManagerEvent event) {
+ ColorGuess* app = context;
+ bool consumed = false;
+
+ if(event.type == SceneManagerEventTypeCustom) {
+ switch(event.event) {
+ case ColorGuessCustomEventPlayLeft:
+ case ColorGuessCustomEventPlayRight:
+ break;
+ case ColorGuessCustomEventPlayUp:
+ case ColorGuessCustomEventPlayDown:
+ break;
+ case ColorGuessCustomEventPlayBack:
+ notification_message(app->notification, &sequence_reset_red);
+ notification_message(app->notification, &sequence_reset_green);
+ notification_message(app->notification, &sequence_reset_blue);
+ if(!scene_manager_search_and_switch_to_previous_scene(
+ app->scene_manager, ColorGuessSceneMenu)) {
+ scene_manager_stop(app->scene_manager);
+ view_dispatcher_stop(app->view_dispatcher);
+ }
+ consumed = true;
+ break;
+ }
+ }
+
+ return consumed;
+}
+
+void color_guess_scene_play_on_exit(void* context) {
+ ColorGuess* app = context;
+ UNUSED(app);
+}
\ No newline at end of file
diff --git a/scenes/color_guess_scene_settings.c b/scenes/color_guess_scene_settings.c
new file mode 100644
index 00000000000..d23fa3fb352
--- /dev/null
+++ b/scenes/color_guess_scene_settings.c
@@ -0,0 +1,116 @@
+#include "../color_guess.h"
+#include
+
+enum SettingsIndex {
+ SettingsIndexHaptic = 10,
+ SettingsIndexValue1,
+ SettingsIndexValue2,
+};
+
+const char* const haptic_text[2] = {
+ "OFF",
+ "ON",
+};
+const uint32_t haptic_value[2] = {
+ ColorGuessHapticOff,
+ ColorGuessHapticOn,
+};
+
+/* Speaker currently not used
+const char* const speaker_text[2] = {
+ "OFF",
+ "ON",
+};
+const uint32_t speaker_value[2] = {
+ ColorGuessSpeakerOff,
+ ColorGuessSpeakerOn,
+};
+*/
+
+/* Game doesn't make sense with LED off, but the setting is there */
+const char* const led_text[2] = {
+ "OFF",
+ "ON",
+};
+const uint32_t led_value[2] = {
+ ColorGuessLedOff,
+ ColorGuessLedOn,
+};
+
+static void color_guess_scene_settings_set_haptic(VariableItem* item) {
+ ColorGuess* app = variable_item_get_context(item);
+ uint8_t index = variable_item_get_current_value_index(item);
+
+ variable_item_set_current_value_text(item, haptic_text[index]);
+ app->haptic = haptic_value[index];
+}
+
+/*
+static void color_guess_scene_settings_set_speaker(VariableItem* item) {
+ ColorGuess* app = variable_item_get_context(item);
+ uint8_t index = variable_item_get_current_value_index(item);
+ variable_item_set_current_value_text(item, speaker_text[index]);
+ app->speaker = speaker_value[index];
+}
+*/
+
+static void color_guess_scene_settings_set_led(VariableItem* item) {
+ ColorGuess* app = variable_item_get_context(item);
+ uint8_t index = variable_item_get_current_value_index(item);
+ variable_item_set_current_value_text(item, led_text[index]);
+ app->led = led_value[index];
+}
+
+void color_guess_scene_settings_submenu_callback(void* context, uint32_t index) {
+ ColorGuess* app = context;
+ view_dispatcher_send_custom_event(app->view_dispatcher, index);
+}
+
+void color_guess_scene_settings_on_enter(void* context) {
+ ColorGuess* app = context;
+ VariableItem* item;
+ uint8_t value_index;
+
+ // Vibro on/off
+ item = variable_item_list_add(
+ app->variable_item_list, "Vibro/Haptic:", 2, color_guess_scene_settings_set_haptic, app);
+ value_index = value_index_uint32(app->haptic, haptic_value, 2);
+ variable_item_set_current_value_index(item, value_index);
+ variable_item_set_current_value_text(item, haptic_text[value_index]);
+
+ // Sound on/off
+ /*
+ item = variable_item_list_add(
+ app->variable_item_list,
+ "Sound:",
+ 2,
+ color_guess_scene_settings_set_speaker,
+ app);
+ value_index = value_index_uint32(app->speaker, speaker_value, 2);
+ variable_item_set_current_value_index(item, value_index);
+ variable_item_set_current_value_text(item, speaker_text[value_index]);*/
+
+ // LED Effects on/off
+ item = variable_item_list_add(
+ app->variable_item_list, "LED FX:", 2, color_guess_scene_settings_set_led, app);
+ value_index = value_index_uint32(app->led, led_value, 2);
+ variable_item_set_current_value_index(item, value_index);
+ variable_item_set_current_value_text(item, led_text[value_index]);
+
+ view_dispatcher_switch_to_view(app->view_dispatcher, ColorGuessViewIdSettings);
+}
+
+bool color_guess_scene_settings_on_event(void* context, SceneManagerEvent event) {
+ ColorGuess* app = context;
+ UNUSED(app);
+ bool consumed = false;
+ if(event.type == SceneManagerEventTypeCustom) {
+ }
+ return consumed;
+}
+
+void color_guess_scene_settings_on_exit(void* context) {
+ ColorGuess* app = context;
+ variable_item_list_set_selected_item(app->variable_item_list, 0);
+ variable_item_list_reset(app->variable_item_list);
+}
\ No newline at end of file
diff --git a/scenes/color_guess_scene_startscreen.c b/scenes/color_guess_scene_startscreen.c
new file mode 100644
index 00000000000..cceba24c663
--- /dev/null
+++ b/scenes/color_guess_scene_startscreen.c
@@ -0,0 +1,53 @@
+#include "../color_guess.h"
+
+void color_guess_scene_startscreen_callback(ColorGuessCustomEvent event, void* context) {
+ furi_assert(context);
+ ColorGuess* app = context;
+ view_dispatcher_send_custom_event(app->view_dispatcher, event);
+}
+
+void color_guess_scene_startscreen_on_enter(void* context) {
+ furi_assert(context);
+ ColorGuess* app = context;
+ color_guess_startscreen_set_callback(
+ app->color_guess_startscreen, color_guess_scene_startscreen_callback, app);
+ view_dispatcher_switch_to_view(app->view_dispatcher, ColorGuessViewIdStartscreen);
+}
+
+bool color_guess_scene_startscreen_on_event(void* context, SceneManagerEvent event) {
+ ColorGuess* app = context;
+ bool consumed = false;
+
+ if(event.type == SceneManagerEventTypeCustom) {
+ switch(event.event) {
+ case ColorGuessCustomEventStartscreenLeft:
+ case ColorGuessCustomEventStartscreenRight:
+ break;
+ case ColorGuessCustomEventStartscreenUp:
+ case ColorGuessCustomEventStartscreenDown:
+ break;
+ case ColorGuessCustomEventStartscreenOk:
+ scene_manager_next_scene(app->scene_manager, ColorGuessSceneMenu);
+ consumed = true;
+ break;
+ case ColorGuessCustomEventStartscreenBack:
+ notification_message(app->notification, &sequence_reset_red);
+ notification_message(app->notification, &sequence_reset_green);
+ notification_message(app->notification, &sequence_reset_blue);
+ if(!scene_manager_search_and_switch_to_previous_scene(
+ app->scene_manager, ColorGuessSceneStartscreen)) {
+ scene_manager_stop(app->scene_manager);
+ view_dispatcher_stop(app->view_dispatcher);
+ }
+ consumed = true;
+ break;
+ }
+ }
+
+ return consumed;
+}
+
+void color_guess_scene_startscreen_on_exit(void* context) {
+ ColorGuess* app = context;
+ UNUSED(app);
+}
\ No newline at end of file
diff --git a/screenshots/color_guess_1.png b/screenshots/color_guess_1.png
new file mode 100644
index 00000000000..608b9dcf2ee
Binary files /dev/null and b/screenshots/color_guess_1.png differ
diff --git a/screenshots/color_guess_2.png b/screenshots/color_guess_2.png
new file mode 100644
index 00000000000..cf696738f44
Binary files /dev/null and b/screenshots/color_guess_2.png differ
diff --git a/screenshots/color_guess_3.png b/screenshots/color_guess_3.png
new file mode 100644
index 00000000000..0364e57de12
Binary files /dev/null and b/screenshots/color_guess_3.png differ
diff --git a/views/color_guess_color_set.c b/views/color_guess_color_set.c
new file mode 100644
index 00000000000..ef41d8ce92f
--- /dev/null
+++ b/views/color_guess_color_set.c
@@ -0,0 +1,184 @@
+#include "../color_guess.h"
+#include "color_guess_icons.h"
+#include "../helpers/color_guess_led.h"
+#include
+#include
+#include
+#include
+#include
+
+struct ColorGuessColorSet {
+ View* view;
+ ColorGuessColorSetCallback callback;
+ void* context;
+};
+
+typedef struct {
+ ColorGuessColorSetStatus status;
+ int cursorpos;
+ int digit[6];
+} ColorGuessColorSetModel;
+
+void color_guess_color_set_set_callback(
+ ColorGuessColorSet* instance,
+ ColorGuessColorSetCallback callback,
+ void* context) {
+ furi_assert(instance);
+ furi_assert(callback);
+ instance->callback = callback;
+ instance->context = context;
+}
+
+void color_guess_color_set_draw(Canvas* canvas, ColorGuessColorSetModel* model) {
+ const int cursorOffset = 30;
+ const int newCursorPos = (model->cursorpos * 12) + cursorOffset;
+
+ canvas_clear(canvas);
+ canvas_set_color(canvas, ColorBlack);
+ canvas_set_font(canvas, FontSecondary);
+ canvas_draw_str(canvas, 5, 7, "Set a custom color on LED");
+
+ canvas_draw_icon(canvas, newCursorPos, 18, &I_ButtonUp_10x5);
+ canvas_draw_icon(canvas, newCursorPos, 41, &I_ButtonDown_10x5);
+ canvas_draw_icon(canvas, 18, 25, digits[16]);
+ canvas_draw_icon(canvas, 30, 25, digits[model->digit[0]]);
+ canvas_draw_icon(canvas, 42, 25, digits[model->digit[1]]);
+ canvas_draw_icon(canvas, 54, 25, digits[model->digit[2]]);
+ canvas_draw_icon(canvas, 66, 25, digits[model->digit[3]]);
+ canvas_draw_icon(canvas, 78, 25, digits[model->digit[4]]);
+ canvas_draw_icon(canvas, 90, 25, digits[model->digit[5]]);
+ elements_button_right(canvas, "See your color here");
+}
+
+static void color_guess_color_set_model_init(ColorGuessColorSetModel* const model) {
+ model->cursorpos = 0;
+ for(int i = 0; i < 6; i++) {
+ model->digit[i] = 0;
+ }
+}
+
+void color_guess_color_set_set_led(void* context, ColorGuessColorSetModel* model) {
+ furi_assert(context);
+ ColorGuess* app = context;
+ color_guess_led_set_rgb(
+ app,
+ (model->digit[0] * 16) + model->digit[1],
+ (model->digit[2] * 16) + model->digit[3],
+ (model->digit[4] * 16) + model->digit[5]);
+}
+
+bool color_guess_color_set_input(InputEvent* event, void* context) {
+ furi_assert(context);
+ ColorGuessColorSet* instance = context;
+ if(event->type == InputTypeRelease) {
+ switch(event->key) {
+ case InputKeyBack:
+ with_view_model(
+ instance->view,
+ ColorGuessColorSetModel * model,
+ {
+ UNUSED(model);
+ instance->callback(ColorGuessCustomEventColorSetBack, instance->context);
+ },
+ true);
+ break;
+ case InputKeyLeft:
+ with_view_model(
+ instance->view,
+ ColorGuessColorSetModel * model,
+ {
+ model->cursorpos--;
+ if(model->cursorpos < 0) {
+ model->cursorpos = 5;
+ }
+ },
+ true);
+ break;
+ case InputKeyRight:
+ with_view_model(
+ instance->view,
+ ColorGuessColorSetModel * model,
+ {
+ model->cursorpos++;
+ if(model->cursorpos > 5) {
+ model->cursorpos = 0;
+ }
+ },
+ true);
+ break;
+ case InputKeyUp:
+ with_view_model(
+ instance->view,
+ ColorGuessColorSetModel * model,
+ {
+ model->digit[model->cursorpos]++;
+ if(model->digit[model->cursorpos] > 15) {
+ model->digit[model->cursorpos] = 0;
+ }
+ color_guess_color_set_set_led(instance->context, model);
+ },
+ true);
+ break;
+ case InputKeyDown:
+ with_view_model(
+ instance->view,
+ ColorGuessColorSetModel * model,
+ {
+ model->digit[model->cursorpos]--;
+ if(model->digit[model->cursorpos] < 0) {
+ model->digit[model->cursorpos] = 15;
+ }
+ color_guess_color_set_set_led(instance->context, model);
+ },
+ true);
+ break;
+ case InputKeyOk:
+ case InputKeyMAX:
+ break;
+ }
+ }
+
+ return true;
+}
+
+void color_guess_color_set_exit(void* context) {
+ furi_assert(context);
+}
+
+void color_guess_color_set_enter(void* context) {
+ furi_assert(context);
+ dolphin_deed(DolphinDeedPluginStart);
+ // ColorGuessColorSet* instance = context;
+}
+
+ColorGuessColorSet* color_guess_color_set_alloc() {
+ ColorGuessColorSet* instance = malloc(sizeof(ColorGuessColorSet));
+ instance->view = view_alloc();
+ view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(ColorGuessColorSetModel));
+ view_set_context(instance->view, instance);
+ view_set_draw_callback(instance->view, (ViewDrawCallback)color_guess_color_set_draw);
+ view_set_input_callback(instance->view, color_guess_color_set_input);
+ //view_set_enter_callback(instance->view, color_guess_color_set_enter);
+ //view_set_exit_callback(instance->view, color_guess_color_set_exit);
+
+ with_view_model(
+ instance->view,
+ ColorGuessColorSetModel * model,
+ { color_guess_color_set_model_init(model); },
+ true);
+
+ return instance;
+}
+
+void color_guess_color_set_free(ColorGuessColorSet* instance) {
+ furi_assert(instance);
+
+ view_free(instance->view);
+ free(instance);
+}
+
+View* color_guess_color_set_get_view(ColorGuessColorSet* instance) {
+ furi_assert(instance);
+
+ return instance->view;
+}
diff --git a/views/color_guess_color_set.h b/views/color_guess_color_set.h
new file mode 100644
index 00000000000..c430c679a97
--- /dev/null
+++ b/views/color_guess_color_set.h
@@ -0,0 +1,24 @@
+#pragma once
+
+#include
+#include "../helpers/color_guess_custom_event.h"
+
+typedef struct ColorGuessColorSet ColorGuessColorSet;
+
+typedef void (*ColorGuessColorSetCallback)(ColorGuessCustomEvent event, void* context);
+
+typedef enum {
+ ColorGuessColorSetStatusStart,
+ ColorGuessColorSetStatusIDLE,
+} ColorGuessColorSetStatus;
+
+void color_guess_color_set_set_callback(
+ ColorGuessColorSet* instance,
+ ColorGuessColorSetCallback callback,
+ void* context);
+
+ColorGuessColorSet* color_guess_color_set_alloc();
+
+void color_guess_color_set_free(ColorGuessColorSet* color_guess_static);
+
+View* color_guess_color_set_get_view(ColorGuessColorSet* color_guess_static);
diff --git a/views/color_guess_play.c b/views/color_guess_play.c
new file mode 100644
index 00000000000..4fe1f6f67f0
--- /dev/null
+++ b/views/color_guess_play.c
@@ -0,0 +1,333 @@
+#include "../color_guess.h"
+#include "color_guess_icons.h"
+#include "../helpers/color_guess_colors.h"
+#include "../helpers/color_guess_haptic.h"
+#include "../helpers/color_guess_led.h"
+#include
+#include
+#include
+#include
+#include
+
+struct ColorGuessPlay {
+ View* view;
+ ColorGuessPlayCallback callback;
+ void* context;
+};
+
+typedef struct {
+ ColorGuessPlayStatus status;
+ int cursorpos;
+ int digit[6];
+ int color;
+ int time_spent;
+ int timestamp_start;
+ int prev_closeness;
+ int closeness;
+ int difficulty;
+ int success;
+} ColorGuessPlayModel;
+
+void color_guess_play_set_callback(
+ ColorGuessPlay* instance,
+ ColorGuessPlayCallback callback,
+ void* context) {
+ furi_assert(instance);
+ furi_assert(callback);
+ instance->callback = callback;
+ instance->context = context;
+}
+
+void play_haptic(void* context, ColorGuessPlayModel* model) {
+ ColorGuess* app = context;
+ if(model->success == 1) {
+ color_guess_play_long_bump(app);
+ } else if(model->closeness > model->prev_closeness) {
+ color_guess_play_happy_bump(app);
+ } else if(model->closeness < model->prev_closeness) {
+ color_guess_play_bad_bump(app);
+ }
+}
+
+void color_guess_play_new_round(void* context, ColorGuessPlayModel* model) {
+ furi_assert(context);
+ ColorGuess* app = context;
+ //Reset timer
+ FuriHalRtcDateTime date_time;
+ furi_hal_rtc_get_datetime(&date_time);
+ model->timestamp_start = furi_hal_rtc_datetime_to_timestamp(&date_time);
+ model->success = 0;
+ model->closeness = 0;
+ model->prev_closeness = 0;
+
+ if(model->difficulty == 0) {
+ model->color = colorsEasy[rand() % ARR_SIZE(colorsEasy)];
+ } else if(model->difficulty == 1) {
+ model->color = colorsNormal[rand() % ARR_SIZE(colorsNormal)];
+ } else if(model->difficulty == 2) {
+ model->color = colorsHard[rand() % ARR_SIZE(colorsHard)];
+ }
+
+ color_guess_led_set_rgb(
+ app, ((model->color >> 16) & 0xFF), ((model->color >> 8) & 0xFF), ((model->color) & 0xFF));
+}
+
+void color_guess_play_calculate_closeness(void* context, ColorGuessPlayModel* model) {
+ furi_assert(context);
+ ColorGuess* app = context;
+ UNUSED(app);
+ int userRed = (model->digit[0] * 16) + model->digit[1];
+ int userGreen = (model->digit[2] * 16) + model->digit[3];
+ int userBlue = (model->digit[4] * 16) + model->digit[5];
+ int ledRed = ((model->color >> 16) & 0xFF);
+ int ledGreen = ((model->color >> 8) & 0xFF);
+ int ledBlue = ((model->color) & 0xFF);
+
+ int distanceRed = abs(ledRed - userRed);
+ int distanceGreen = abs(ledGreen - userGreen);
+ int distanceBlue = abs(ledBlue - userBlue);
+ float percentageRed = 100 - ((distanceRed / 255.0) *
+ 100); //make sure one number is float, otherwise C will calc wrong
+ float percentageGreen = 100 - ((distanceGreen / 255.0) * 100);
+ float percentageBlue = 100 - ((distanceBlue / 255.0) * 100);
+ if(percentageRed == 100 && percentageGreen == 100 && percentageBlue == 100) {
+ model->success = 1;
+ dolphin_deed(DolphinDeedPluginGameWin);
+ }
+ float fullPercentage = (percentageRed + percentageGreen + percentageBlue) / 3;
+ model->prev_closeness = model->closeness;
+ model->closeness = round(fullPercentage);
+}
+
+void parse_time_str(char* buffer, int32_t sec) {
+ snprintf(
+ buffer,
+ TIMER_LENGHT,
+ TIMER_FORMAT,
+ (sec % (60 * 60)) / 60, // minute
+ sec % 60); // second
+}
+
+void drawDifficulty(Canvas* canvas, ColorGuessPlayModel* model) {
+ UNUSED(model);
+ char* strDifficulty = malloc(7);
+ if(model->difficulty == 0) {
+ strcpy(strDifficulty, "Easy");
+ } else if(model->difficulty == 1) {
+ strcpy(strDifficulty, "Medium");
+ } else if(model->difficulty == 2) {
+ strcpy(strDifficulty, "Hard");
+ }
+ canvas_draw_box(canvas, 0, 52, 47, 12);
+ canvas_invert_color(canvas);
+ canvas_draw_icon(canvas, 2, 54, &I_ButtonCenter_7x7);
+ canvas_draw_str_aligned(canvas, 11, 54, AlignLeft, AlignTop, strDifficulty);
+ canvas_invert_color(canvas);
+ free(strDifficulty);
+ furi_thread_flags_wait(0, FuriFlagWaitAny, 10);
+}
+
+void color_guess_play_draw(Canvas* canvas, ColorGuessPlayModel* model) {
+ char timer_string[TIMER_LENGHT];
+ if(model->success == 1) {
+ parse_time_str(timer_string, model->time_spent);
+ canvas_clear(canvas);
+ canvas_set_color(canvas, ColorBlack);
+ canvas_set_font(canvas, FontPrimary);
+ canvas_draw_str_aligned(canvas, 64, 2, AlignCenter, AlignTop, "You won!!");
+ canvas_set_font(canvas, FontSecondary);
+ elements_button_center(canvas, "New Round");
+ canvas_set_font(canvas, FontBigNumbers);
+ canvas_draw_str_aligned(canvas, 64, 16, AlignCenter, AlignTop, timer_string);
+
+ canvas_draw_icon(canvas, 18, 32, digits[16]);
+ canvas_draw_icon(canvas, 30, 32, digits[model->digit[0]]);
+ canvas_draw_icon(canvas, 42, 32, digits[model->digit[1]]);
+ canvas_draw_icon(canvas, 54, 32, digits[model->digit[2]]);
+ canvas_draw_icon(canvas, 66, 32, digits[model->digit[3]]);
+ canvas_draw_icon(canvas, 78, 32, digits[model->digit[4]]);
+ canvas_draw_icon(canvas, 90, 32, digits[model->digit[5]]);
+
+ return;
+ }
+ const int cursorOffset = 30;
+ const int newCursorPos = (model->cursorpos * 12) + cursorOffset;
+ FuriHalRtcDateTime date_time;
+ furi_hal_rtc_get_datetime(&date_time);
+ uint32_t timestamp = furi_hal_rtc_datetime_to_timestamp(&date_time);
+ uint32_t time_elapsed = timestamp - model->timestamp_start;
+ model->time_spent = time_elapsed;
+
+ char closeness_string[4];
+
+ parse_time_str(timer_string, time_elapsed);
+ snprintf(closeness_string, CLOSENESS_LENGTH, CLOSENESS_FORMAT, model->closeness);
+
+ canvas_clear(canvas);
+ canvas_set_color(canvas, ColorBlack);
+ canvas_set_font(canvas, FontSecondary);
+ canvas_draw_str_aligned(canvas, 0, 0, AlignLeft, AlignTop, "Time spent:");
+ canvas_draw_str_aligned(canvas, 55, 0, AlignLeft, AlignTop, timer_string); // DRAW TIMER
+ canvas_draw_str_aligned(canvas, 0, 9, AlignLeft, AlignTop, "You are this close:");
+ canvas_draw_str_aligned(canvas, 105, 9, AlignLeft, AlignTop, closeness_string);
+
+ canvas_draw_icon(canvas, newCursorPos, 20, &I_ButtonUp_10x5);
+ canvas_draw_icon(canvas, newCursorPos, 43, &I_ButtonDown_10x5);
+ canvas_draw_icon(canvas, 18, 27, digits[16]);
+ canvas_draw_icon(canvas, 30, 27, digits[model->digit[0]]);
+ canvas_draw_icon(canvas, 42, 27, digits[model->digit[1]]);
+ canvas_draw_icon(canvas, 54, 27, digits[model->digit[2]]);
+ canvas_draw_icon(canvas, 66, 27, digits[model->digit[3]]);
+ canvas_draw_icon(canvas, 78, 27, digits[model->digit[4]]);
+ canvas_draw_icon(canvas, 90, 27, digits[model->digit[5]]);
+ elements_button_right(canvas, "Guess this color");
+ drawDifficulty(canvas, model);
+}
+
+static void color_guess_play_model_init(ColorGuessPlayModel* const model) {
+ model->cursorpos = 0;
+ for(int i = 0; i < 6; i++) {
+ model->digit[i] = 0;
+ }
+ model->closeness = 0;
+ model->difficulty = 1;
+}
+
+bool color_guess_play_input(InputEvent* event, void* context) {
+ furi_assert(context);
+ ColorGuessPlay* instance = context;
+ if(event->type == InputTypeRelease) {
+ switch(event->key) {
+ case InputKeyBack:
+ with_view_model(
+ instance->view,
+ ColorGuessPlayModel * model,
+ {
+ UNUSED(model);
+ instance->callback(ColorGuessCustomEventPlayBack, instance->context);
+ },
+ true);
+ break;
+ case InputKeyLeft:
+ with_view_model(
+ instance->view,
+ ColorGuessPlayModel * model,
+ {
+ model->cursorpos--;
+ if(model->cursorpos < 0) {
+ model->cursorpos = 5;
+ }
+ },
+ true);
+ break;
+ case InputKeyRight:
+ with_view_model(
+ instance->view,
+ ColorGuessPlayModel * model,
+ {
+ model->cursorpos++;
+ if(model->cursorpos > 5) {
+ model->cursorpos = 0;
+ }
+ },
+ true);
+ break;
+ case InputKeyUp:
+ with_view_model(
+ instance->view,
+ ColorGuessPlayModel * model,
+ {
+ model->digit[model->cursorpos]++;
+ if(model->digit[model->cursorpos] > 15) {
+ model->digit[model->cursorpos] = 0;
+ }
+ color_guess_play_calculate_closeness(instance, model);
+ play_haptic(instance->context, model);
+ },
+ true);
+ break;
+ case InputKeyDown:
+ with_view_model(
+ instance->view,
+ ColorGuessPlayModel * model,
+ {
+ model->digit[model->cursorpos]--;
+ if(model->digit[model->cursorpos] < 0) {
+ model->digit[model->cursorpos] = 15;
+ }
+ color_guess_play_calculate_closeness(instance, model);
+ play_haptic(instance->context, model);
+ },
+ true);
+ break;
+ case InputKeyOk:
+ with_view_model(
+ instance->view,
+ ColorGuessPlayModel * model,
+ {
+ if(model->success == 1) {
+ model->success = 0;
+ } else {
+ model->difficulty++;
+ if(model->difficulty > 2) {
+ model->difficulty = 0;
+ }
+ }
+ color_guess_play_new_round(instance->context, model);
+ },
+ true);
+ break;
+ case InputKeyMAX:
+ break;
+ }
+ }
+ return true;
+}
+
+void color_guess_play_exit(void* context) {
+ furi_assert(context);
+}
+
+void color_guess_play_enter(void* context) {
+ furi_assert(context);
+ ColorGuessPlay* instance = (ColorGuessPlay*)context;
+ dolphin_deed(DolphinDeedPluginGameStart);
+ with_view_model(
+ instance->view,
+ ColorGuessPlayModel * model,
+ {
+ color_guess_play_model_init(model);
+ color_guess_play_new_round(instance->context, model);
+ },
+ true);
+}
+
+ColorGuessPlay* color_guess_play_alloc() {
+ ColorGuessPlay* instance = malloc(sizeof(ColorGuessPlay));
+ instance->view = view_alloc();
+ view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(ColorGuessPlayModel));
+ view_set_context(instance->view, instance); // furi_assert crashes in events without this
+ view_set_draw_callback(instance->view, (ViewDrawCallback)color_guess_play_draw);
+ view_set_input_callback(instance->view, color_guess_play_input);
+ view_set_enter_callback(instance->view, color_guess_play_enter);
+ //view_set_exit_callback(instance->view, color_guess_play_exit);
+
+ with_view_model(
+ instance->view, ColorGuessPlayModel * model, { color_guess_play_model_init(model); }, true);
+
+ return instance;
+}
+
+void color_guess_play_free(ColorGuessPlay* instance) {
+ furi_assert(instance);
+
+ with_view_model(
+ instance->view, ColorGuessPlayModel * model, { free(model->digit); }, true);
+ view_free(instance->view);
+ free(instance);
+}
+
+View* color_guess_play_get_view(ColorGuessPlay* instance) {
+ furi_assert(instance);
+ return instance->view;
+}
diff --git a/views/color_guess_play.h b/views/color_guess_play.h
new file mode 100644
index 00000000000..f9f630c40bf
--- /dev/null
+++ b/views/color_guess_play.h
@@ -0,0 +1,32 @@
+#pragma once
+
+#include
+#include "../helpers/color_guess_custom_event.h"
+
+extern const Icon* digits[17];
+
+#define TIMER_FORMAT "%02ld:%02ld" //"%.2d:%.2d"
+#define TIMER_LENGHT 13
+#define CLOSENESS_LENGTH 7
+#define CLOSENESS_FORMAT "%d%%"
+#define ARR_SIZE(arr) (sizeof((arr)) / sizeof((arr[0])))
+
+typedef struct ColorGuessPlay ColorGuessPlay;
+
+typedef void (*ColorGuessPlayCallback)(ColorGuessCustomEvent event, void* context);
+
+typedef enum {
+ ColorGuessPlayStatusStart,
+ ColorGuessPlayStatusIDLE,
+} ColorGuessPlayStatus;
+
+void color_guess_play_set_callback(
+ ColorGuessPlay* color_guess_play,
+ ColorGuessPlayCallback callback,
+ void* context);
+
+View* color_guess_play_get_view(ColorGuessPlay* color_guess_static);
+
+ColorGuessPlay* color_guess_play_alloc();
+
+void color_guess_play_free(ColorGuessPlay* color_guess_static);
\ No newline at end of file
diff --git a/views/color_guess_startscreen.c b/views/color_guess_startscreen.c
new file mode 100644
index 00000000000..a837574807b
--- /dev/null
+++ b/views/color_guess_startscreen.c
@@ -0,0 +1,127 @@
+#include "../color_guess.h"
+#include
+#include
+#include
+#include
+#include
+#include "color_guess_icons.h"
+
+struct ColorGuessStartscreen {
+ View* view;
+ ColorGuessStartscreenCallback callback;
+ void* context;
+};
+
+typedef struct {
+ int some_value;
+} ColorGuessStartscreenModel;
+
+void color_guess_startscreen_set_callback(
+ ColorGuessStartscreen* instance,
+ ColorGuessStartscreenCallback callback,
+ void* context) {
+ furi_assert(instance);
+ furi_assert(callback);
+ instance->callback = callback;
+ instance->context = context;
+}
+
+void color_guess_startscreen_draw(Canvas* canvas, ColorGuessStartscreenModel* model) {
+ UNUSED(model);
+ canvas_clear(canvas);
+ canvas_set_color(canvas, ColorBlack);
+ canvas_set_font(canvas, FontPrimary);
+ canvas_draw_icon(canvas, 0, 9, &I_start_dolph_49x55);
+ canvas_draw_str_aligned(canvas, 64, 10, AlignCenter, AlignTop, "Color Guess");
+ canvas_set_font(canvas, FontSecondary);
+ canvas_draw_str_aligned(canvas, 54, 22, AlignLeft, AlignTop, "Guess the color");
+ canvas_draw_str_aligned(canvas, 54, 32, AlignLeft, AlignTop, "on Flipper's LED");
+ elements_button_center(canvas, "Start");
+}
+
+static void color_guess_startscreen_model_init(ColorGuessStartscreenModel* const model) {
+ model->some_value = 1;
+}
+
+bool color_guess_startscreen_input(InputEvent* event, void* context) {
+ furi_assert(context);
+ ColorGuessStartscreen* instance = context;
+ if(event->type == InputTypeRelease) {
+ switch(event->key) {
+ case InputKeyBack:
+ with_view_model(
+ instance->view,
+ ColorGuessStartscreenModel * model,
+ {
+ UNUSED(model);
+ instance->callback(ColorGuessCustomEventStartscreenBack, instance->context);
+ },
+ true);
+ break;
+ case InputKeyLeft:
+ case InputKeyRight:
+ case InputKeyUp:
+ case InputKeyDown:
+ case InputKeyOk:
+ with_view_model(
+ instance->view,
+ ColorGuessStartscreenModel * model,
+ {
+ UNUSED(model);
+ instance->callback(ColorGuessCustomEventStartscreenOk, instance->context);
+ },
+ true);
+ break;
+ case InputKeyMAX:
+ break;
+ }
+ }
+ return true;
+}
+
+void color_guess_startscreen_exit(void* context) {
+ furi_assert(context);
+}
+
+void color_guess_startscreen_enter(void* context) {
+ furi_assert(context);
+ ColorGuessStartscreen* instance = (ColorGuessStartscreen*)context;
+ with_view_model(
+ instance->view,
+ ColorGuessStartscreenModel * model,
+ { color_guess_startscreen_model_init(model); },
+ true);
+}
+
+ColorGuessStartscreen* color_guess_startscreen_alloc() {
+ ColorGuessStartscreen* instance = malloc(sizeof(ColorGuessStartscreen));
+ instance->view = view_alloc();
+ view_allocate_model(instance->view, ViewModelTypeLocking, sizeof(ColorGuessStartscreenModel));
+ view_set_context(instance->view, instance); // furi_assert crashes in events without this
+ view_set_draw_callback(instance->view, (ViewDrawCallback)color_guess_startscreen_draw);
+ view_set_input_callback(instance->view, color_guess_startscreen_input);
+ //view_set_enter_callback(instance->view, color_guess_startscreen_enter);
+ //view_set_exit_callback(instance->view, color_guess_startscreen_exit);
+
+ with_view_model(
+ instance->view,
+ ColorGuessStartscreenModel * model,
+ { color_guess_startscreen_model_init(model); },
+ true);
+
+ return instance;
+}
+
+void color_guess_startscreen_free(ColorGuessStartscreen* instance) {
+ furi_assert(instance);
+
+ with_view_model(
+ instance->view, ColorGuessStartscreenModel * model, { UNUSED(model); }, true);
+ view_free(instance->view);
+ free(instance);
+}
+
+View* color_guess_startscreen_get_view(ColorGuessStartscreen* instance) {
+ furi_assert(instance);
+ return instance->view;
+}
diff --git a/views/color_guess_startscreen.h b/views/color_guess_startscreen.h
new file mode 100644
index 00000000000..7474629b46c
--- /dev/null
+++ b/views/color_guess_startscreen.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include
+#include "../helpers/color_guess_custom_event.h"
+
+typedef struct ColorGuessStartscreen ColorGuessStartscreen;
+
+typedef void (*ColorGuessStartscreenCallback)(ColorGuessCustomEvent event, void* context);
+
+void color_guess_startscreen_set_callback(
+ ColorGuessStartscreen* color_guess_startscreen,
+ ColorGuessStartscreenCallback callback,
+ void* context);
+
+View* color_guess_startscreen_get_view(ColorGuessStartscreen* color_guess_static);
+
+ColorGuessStartscreen* color_guess_startscreen_alloc();
+
+void color_guess_startscreen_free(ColorGuessStartscreen* color_guess_static);
\ No newline at end of file