[FL-2627] Flipper applications: SDK, build and debug system (#1387)
* Added support for running applications from SD card (FAPs - Flipper Application Packages) * Added plugin_dist target for fbt to build FAPs * All apps of type FlipperAppType.EXTERNAL and FlipperAppType.PLUGIN are built as FAPs by default * Updated VSCode configuration for new fbt features - re-deploy stock configuration to use them * Added debugging support for FAPs with fbt debug & VSCode * Added public firmware API with automated versioning Co-authored-by: hedger <hedger@users.noreply.github.com> Co-authored-by: SG <who.just.the.doctor@gmail.com> Co-authored-by: あく <alleteam@gmail.com>
This commit is contained in:
211
applications/settings/about/about.c
Normal file
211
applications/settings/about/about.c
Normal file
@@ -0,0 +1,211 @@
|
||||
#include <furi.h>
|
||||
#include <dialogs/dialogs.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/modules/empty_screen.h>
|
||||
#include <m-string.h>
|
||||
#include <furi_hal_version.h>
|
||||
#include <furi_hal_region.h>
|
||||
#include <furi_hal_bt.h>
|
||||
|
||||
typedef DialogMessageButton (*AboutDialogScreen)(DialogsApp* dialogs, DialogMessage* message);
|
||||
|
||||
static DialogMessageButton product_screen(DialogsApp* dialogs, DialogMessage* message) {
|
||||
DialogMessageButton result;
|
||||
|
||||
const char* screen_header = "Product: Flipper Zero\n"
|
||||
"Model: FZ.1\n";
|
||||
const char* screen_text = "FCC ID: 2A2V6-FZ\n"
|
||||
"IC: 27624-FZ";
|
||||
|
||||
dialog_message_set_header(message, screen_header, 0, 0, AlignLeft, AlignTop);
|
||||
dialog_message_set_text(message, screen_text, 0, 26, AlignLeft, AlignTop);
|
||||
result = dialog_message_show(dialogs, message);
|
||||
dialog_message_set_header(message, NULL, 0, 0, AlignLeft, AlignTop);
|
||||
dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static DialogMessageButton address_screen(DialogsApp* dialogs, DialogMessage* message) {
|
||||
DialogMessageButton result;
|
||||
|
||||
const char* screen_text = "Flipper Devices Inc\n"
|
||||
"Suite B #551, 2803\n"
|
||||
"Philadelphia Pike, Claymont\n"
|
||||
"DE, USA 19703\n";
|
||||
|
||||
dialog_message_set_text(message, screen_text, 0, 0, AlignLeft, AlignTop);
|
||||
result = dialog_message_show(dialogs, message);
|
||||
dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static DialogMessageButton compliance_screen(DialogsApp* dialogs, DialogMessage* message) {
|
||||
DialogMessageButton result;
|
||||
|
||||
const char* screen_text = "For all compliance\n"
|
||||
"certificates please visit:\n"
|
||||
"www.flipp.dev/compliance";
|
||||
|
||||
dialog_message_set_text(message, screen_text, 0, 0, AlignLeft, AlignTop);
|
||||
result = dialog_message_show(dialogs, message);
|
||||
dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static DialogMessageButton icon1_screen(DialogsApp* dialogs, DialogMessage* message) {
|
||||
DialogMessageButton result;
|
||||
|
||||
dialog_message_set_icon(message, &I_Certification1_103x56, 13, 0);
|
||||
result = dialog_message_show(dialogs, message);
|
||||
dialog_message_set_icon(message, NULL, 0, 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static DialogMessageButton icon2_screen(DialogsApp* dialogs, DialogMessage* message) {
|
||||
DialogMessageButton result;
|
||||
|
||||
dialog_message_set_icon(message, &I_Certification2_98x33, 15, 10);
|
||||
result = dialog_message_show(dialogs, message);
|
||||
dialog_message_set_icon(message, NULL, 0, 0);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static DialogMessageButton hw_version_screen(DialogsApp* dialogs, DialogMessage* message) {
|
||||
DialogMessageButton result;
|
||||
string_t buffer;
|
||||
string_init(buffer);
|
||||
const char* my_name = furi_hal_version_get_name_ptr();
|
||||
|
||||
string_cat_printf(
|
||||
buffer,
|
||||
"%d.F%dB%dC%d %s:%s %s\n",
|
||||
furi_hal_version_get_hw_version(),
|
||||
furi_hal_version_get_hw_target(),
|
||||
furi_hal_version_get_hw_body(),
|
||||
furi_hal_version_get_hw_connect(),
|
||||
furi_hal_version_get_hw_region_name(),
|
||||
furi_hal_region_get_name(),
|
||||
my_name ? my_name : "Unknown");
|
||||
|
||||
string_cat_printf(buffer, "Serial Number:\n");
|
||||
const uint8_t* uid = furi_hal_version_uid();
|
||||
for(size_t i = 0; i < furi_hal_version_uid_size(); i++) {
|
||||
string_cat_printf(buffer, "%02X", uid[i]);
|
||||
}
|
||||
|
||||
dialog_message_set_header(message, "HW Version Info:", 0, 0, AlignLeft, AlignTop);
|
||||
dialog_message_set_text(message, string_get_cstr(buffer), 0, 13, AlignLeft, AlignTop);
|
||||
result = dialog_message_show(dialogs, message);
|
||||
dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop);
|
||||
dialog_message_set_header(message, NULL, 0, 0, AlignLeft, AlignTop);
|
||||
string_clear(buffer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static DialogMessageButton fw_version_screen(DialogsApp* dialogs, DialogMessage* message) {
|
||||
DialogMessageButton result;
|
||||
string_t buffer;
|
||||
string_init(buffer);
|
||||
const Version* ver = furi_hal_version_get_firmware_version();
|
||||
const BleGlueC2Info* c2_ver = NULL;
|
||||
#ifdef SRV_BT
|
||||
c2_ver = ble_glue_get_c2_info();
|
||||
#endif
|
||||
|
||||
if(!ver) {
|
||||
string_cat_printf(buffer, "No info\n");
|
||||
} else {
|
||||
string_cat_printf(
|
||||
buffer,
|
||||
"%s [%s]\n%s%s [%s] %s\n[%d] %s",
|
||||
version_get_version(ver),
|
||||
version_get_builddate(ver),
|
||||
version_get_dirty_flag(ver) ? "[!] " : "",
|
||||
version_get_githash(ver),
|
||||
version_get_gitbranchnum(ver),
|
||||
c2_ver ? c2_ver->StackTypeString : "<none>",
|
||||
version_get_target(ver),
|
||||
version_get_gitbranch(ver));
|
||||
}
|
||||
|
||||
dialog_message_set_header(message, "FW Version Info:", 0, 0, AlignLeft, AlignTop);
|
||||
dialog_message_set_text(message, string_get_cstr(buffer), 0, 13, AlignLeft, AlignTop);
|
||||
result = dialog_message_show(dialogs, message);
|
||||
dialog_message_set_text(message, NULL, 0, 0, AlignLeft, AlignTop);
|
||||
dialog_message_set_header(message, NULL, 0, 0, AlignLeft, AlignTop);
|
||||
string_clear(buffer);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const AboutDialogScreen about_screens[] = {
|
||||
product_screen,
|
||||
compliance_screen,
|
||||
address_screen,
|
||||
icon1_screen,
|
||||
icon2_screen,
|
||||
hw_version_screen,
|
||||
fw_version_screen};
|
||||
|
||||
const size_t about_screens_count = sizeof(about_screens) / sizeof(AboutDialogScreen);
|
||||
|
||||
int32_t about_settings_app(void* p) {
|
||||
UNUSED(p);
|
||||
DialogsApp* dialogs = furi_record_open(RECORD_DIALOGS);
|
||||
DialogMessage* message = dialog_message_alloc();
|
||||
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
ViewDispatcher* view_dispatcher = view_dispatcher_alloc();
|
||||
EmptyScreen* empty_screen = empty_screen_alloc();
|
||||
const uint32_t empty_screen_index = 0;
|
||||
|
||||
size_t screen_index = 0;
|
||||
DialogMessageButton screen_result;
|
||||
|
||||
// draw empty screen to prevent menu flickering
|
||||
view_dispatcher_add_view(
|
||||
view_dispatcher, empty_screen_index, empty_screen_get_view(empty_screen));
|
||||
view_dispatcher_attach_to_gui(view_dispatcher, gui, ViewDispatcherTypeFullscreen);
|
||||
view_dispatcher_switch_to_view(view_dispatcher, empty_screen_index);
|
||||
|
||||
while(1) {
|
||||
if(screen_index >= about_screens_count - 1) {
|
||||
dialog_message_set_buttons(message, "Back", NULL, NULL);
|
||||
} else {
|
||||
dialog_message_set_buttons(message, "Back", NULL, "Next");
|
||||
}
|
||||
|
||||
screen_result = about_screens[screen_index](dialogs, message);
|
||||
|
||||
if(screen_result == DialogMessageButtonLeft) {
|
||||
if(screen_index <= 0) {
|
||||
break;
|
||||
} else {
|
||||
screen_index--;
|
||||
}
|
||||
} else if(screen_result == DialogMessageButtonRight) {
|
||||
if(screen_index < about_screens_count) {
|
||||
screen_index++;
|
||||
}
|
||||
} else if(screen_result == DialogMessageButtonBack) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dialog_message_free(message);
|
||||
furi_record_close(RECORD_DIALOGS);
|
||||
|
||||
view_dispatcher_remove_view(view_dispatcher, empty_screen_index);
|
||||
view_dispatcher_free(view_dispatcher);
|
||||
empty_screen_free(empty_screen);
|
||||
furi_record_close(RECORD_GUI);
|
||||
|
||||
return 0;
|
||||
}
|
||||
13
applications/settings/about/application.fam
Normal file
13
applications/settings/about/application.fam
Normal file
@@ -0,0 +1,13 @@
|
||||
App(
|
||||
appid="about",
|
||||
name="About",
|
||||
apptype=FlipperAppType.SETTINGS,
|
||||
entry_point="about_settings_app",
|
||||
cdefines=["APP_ABOUT"],
|
||||
requires=[
|
||||
"gui",
|
||||
"dialogs",
|
||||
],
|
||||
stack_size=1 * 1024,
|
||||
order=1000,
|
||||
)
|
||||
10
applications/settings/application.fam
Normal file
10
applications/settings/application.fam
Normal file
@@ -0,0 +1,10 @@
|
||||
App(
|
||||
appid="settings_apps",
|
||||
name="Basic settings apps bundle",
|
||||
apptype=FlipperAppType.METAPACKAGE,
|
||||
provides=[
|
||||
"passport",
|
||||
"system_settings",
|
||||
"about",
|
||||
],
|
||||
)
|
||||
12
applications/settings/bt_settings_app/application.fam
Normal file
12
applications/settings/bt_settings_app/application.fam
Normal file
@@ -0,0 +1,12 @@
|
||||
App(
|
||||
appid="bt_settings",
|
||||
name="Bluetooth",
|
||||
apptype=FlipperAppType.SETTINGS,
|
||||
entry_point="bt_settings_app",
|
||||
stack_size=1 * 1024,
|
||||
requires=[
|
||||
"bt",
|
||||
"gui",
|
||||
],
|
||||
order=10,
|
||||
)
|
||||
85
applications/settings/bt_settings_app/bt_settings_app.c
Normal file
85
applications/settings/bt_settings_app/bt_settings_app.c
Normal file
@@ -0,0 +1,85 @@
|
||||
#include "bt_settings_app.h"
|
||||
|
||||
static bool bt_settings_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
BtSettingsApp* app = context;
|
||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||
}
|
||||
|
||||
static bool bt_settings_back_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
BtSettingsApp* app = context;
|
||||
return scene_manager_handle_back_event(app->scene_manager);
|
||||
}
|
||||
|
||||
BtSettingsApp* bt_settings_app_alloc() {
|
||||
BtSettingsApp* app = malloc(sizeof(BtSettingsApp));
|
||||
|
||||
// Load settings
|
||||
bt_settings_load(&app->settings);
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
app->bt = furi_record_open(RECORD_BT);
|
||||
|
||||
// View Dispatcher and Scene Manager
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
app->scene_manager = scene_manager_alloc(&bt_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, bt_settings_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
app->view_dispatcher, bt_settings_back_event_callback);
|
||||
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
// Gui Modules
|
||||
app->var_item_list = variable_item_list_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
BtSettingsAppViewVarItemList,
|
||||
variable_item_list_get_view(app->var_item_list));
|
||||
|
||||
app->dialog = dialog_ex_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, BtSettingsAppViewDialog, dialog_ex_get_view(app->dialog));
|
||||
|
||||
app->popup = popup_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, BtSettingsAppViewPopup, popup_get_view(app->popup));
|
||||
|
||||
// Set first scene
|
||||
scene_manager_next_scene(app->scene_manager, BtSettingsAppSceneStart);
|
||||
return app;
|
||||
}
|
||||
|
||||
void bt_settings_app_free(BtSettingsApp* app) {
|
||||
furi_assert(app);
|
||||
// Gui modules
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BtSettingsAppViewVarItemList);
|
||||
variable_item_list_free(app->var_item_list);
|
||||
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BtSettingsAppViewDialog);
|
||||
dialog_ex_free(app->dialog);
|
||||
|
||||
view_dispatcher_remove_view(app->view_dispatcher, BtSettingsAppViewPopup);
|
||||
popup_free(app->popup);
|
||||
|
||||
// View Dispatcher and Scene Manager
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
scene_manager_free(app->scene_manager);
|
||||
|
||||
// Records
|
||||
furi_record_close(RECORD_GUI);
|
||||
furi_record_close(RECORD_BT);
|
||||
free(app);
|
||||
}
|
||||
|
||||
extern int32_t bt_settings_app(void* p) {
|
||||
UNUSED(p);
|
||||
BtSettingsApp* app = bt_settings_app_alloc();
|
||||
view_dispatcher_run(app->view_dispatcher);
|
||||
bt_settings_save(&app->settings);
|
||||
bt_settings_app_free(app);
|
||||
return 0;
|
||||
}
|
||||
41
applications/settings/bt_settings_app/bt_settings_app.h
Normal file
41
applications/settings/bt_settings_app/bt_settings_app.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <bt/bt_service/bt.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
#include <gui/modules/dialog_ex.h>
|
||||
#include <gui/modules/popup.h>
|
||||
|
||||
#include <bt/bt_settings.h>
|
||||
#include "scenes/bt_settings_scene.h"
|
||||
|
||||
enum BtSettingsCustomEvent {
|
||||
// Keep first 10 events reserved for button types and indexes
|
||||
BtSettingsCustomEventReserved = 10,
|
||||
|
||||
BtSettingsCustomEventForgetDevices,
|
||||
BtSettingsCustomEventExitView,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
BtSettings settings;
|
||||
Bt* bt;
|
||||
Gui* gui;
|
||||
SceneManager* scene_manager;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
|
||||
VariableItemList* var_item_list;
|
||||
DialogEx* dialog;
|
||||
Popup* popup;
|
||||
} BtSettingsApp;
|
||||
|
||||
typedef enum {
|
||||
BtSettingsAppViewVarItemList,
|
||||
BtSettingsAppViewDialog,
|
||||
BtSettingsAppViewPopup,
|
||||
} BtSettingsAppView;
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "bt_settings_scene.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const bt_settings_on_enter_handlers[])(void*) = {
|
||||
#include "bt_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 bt_settings_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "bt_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 bt_settings_on_exit_handlers[])(void* context) = {
|
||||
#include "bt_settings_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers bt_settings_scene_handlers = {
|
||||
.on_enter_handlers = bt_settings_on_enter_handlers,
|
||||
.on_event_handlers = bt_settings_on_event_handlers,
|
||||
.on_exit_handlers = bt_settings_on_exit_handlers,
|
||||
.scene_num = BtSettingsAppSceneNum,
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) BtSettingsAppScene##id,
|
||||
typedef enum {
|
||||
#include "bt_settings_scene_config.h"
|
||||
BtSettingsAppSceneNum,
|
||||
} BtSettingsAppScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers bt_settings_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "bt_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 "bt_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 "bt_settings_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
@@ -0,0 +1,3 @@
|
||||
ADD_SCENE(bt_settings, start, Start)
|
||||
ADD_SCENE(bt_settings, forget_dev_confirm, ForgetDevConfirm)
|
||||
ADD_SCENE(bt_settings, forget_dev_success, ForgetDevSuccess)
|
||||
@@ -0,0 +1,44 @@
|
||||
#include "../bt_settings_app.h"
|
||||
#include "furi_hal_bt.h"
|
||||
|
||||
void bt_settings_scene_forget_dev_confirm_dialog_callback(DialogExResult result, void* context) {
|
||||
furi_assert(context);
|
||||
BtSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void bt_settings_scene_forget_dev_confirm_on_enter(void* context) {
|
||||
BtSettingsApp* app = context;
|
||||
DialogEx* dialog = app->dialog;
|
||||
dialog_ex_set_header(dialog, "Unpair All Devices?", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(
|
||||
dialog, "All previous pairings\nwill be lost!", 64, 22, AlignCenter, AlignTop);
|
||||
dialog_ex_set_left_button_text(dialog, "Back");
|
||||
dialog_ex_set_right_button_text(dialog, "Unpair");
|
||||
dialog_ex_set_context(dialog, app);
|
||||
dialog_ex_set_result_callback(dialog, bt_settings_scene_forget_dev_confirm_dialog_callback);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, BtSettingsAppViewDialog);
|
||||
}
|
||||
|
||||
bool bt_settings_scene_forget_dev_confirm_on_event(void* context, SceneManagerEvent event) {
|
||||
BtSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == DialogExResultLeft) {
|
||||
consumed = scene_manager_previous_scene(app->scene_manager);
|
||||
} else if(event.event == DialogExResultRight) {
|
||||
bt_forget_bonded_devices(app->bt);
|
||||
scene_manager_next_scene(app->scene_manager, BtSettingsAppSceneForgetDevSuccess);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void bt_settings_scene_forget_dev_confirm_on_exit(void* context) {
|
||||
BtSettingsApp* app = context;
|
||||
dialog_ex_reset(app->dialog);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "../bt_settings_app.h"
|
||||
#include "furi_hal_bt.h"
|
||||
|
||||
void bt_settings_app_scene_forget_dev_success_popup_callback(void* context) {
|
||||
BtSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, BtSettingsCustomEventExitView);
|
||||
}
|
||||
|
||||
void bt_settings_scene_forget_dev_success_on_enter(void* context) {
|
||||
BtSettingsApp* app = context;
|
||||
Popup* popup = app->popup;
|
||||
|
||||
popup_set_icon(popup, 32, 5, &I_DolphinNice_96x59);
|
||||
popup_set_header(popup, "Done", 14, 15, AlignLeft, AlignTop);
|
||||
popup_set_timeout(popup, 1500);
|
||||
popup_set_context(popup, app);
|
||||
popup_set_callback(popup, bt_settings_app_scene_forget_dev_success_popup_callback);
|
||||
popup_enable_timeout(popup);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, BtSettingsAppViewPopup);
|
||||
}
|
||||
|
||||
bool bt_settings_scene_forget_dev_success_on_event(void* context, SceneManagerEvent event) {
|
||||
BtSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == BtSettingsCustomEventExitView) {
|
||||
if(scene_manager_has_previous_scene(app->scene_manager, BtSettingsAppSceneStart)) {
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, BtSettingsAppSceneStart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void bt_settings_scene_forget_dev_success_on_exit(void* context) {
|
||||
BtSettingsApp* app = context;
|
||||
popup_reset(app->popup);
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
#include "../bt_settings_app.h"
|
||||
#include "furi_hal_bt.h"
|
||||
|
||||
enum BtSetting {
|
||||
BtSettingOff,
|
||||
BtSettingOn,
|
||||
BtSettingNum,
|
||||
};
|
||||
|
||||
enum BtSettingIndex {
|
||||
BtSettingIndexSwitchBt,
|
||||
BtSettingIndexForgetDev,
|
||||
};
|
||||
|
||||
const char* const bt_settings_text[BtSettingNum] = {
|
||||
"OFF",
|
||||
"ON",
|
||||
};
|
||||
|
||||
static void bt_settings_scene_start_var_list_change_callback(VariableItem* item) {
|
||||
BtSettingsApp* app = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
variable_item_set_current_value_text(item, bt_settings_text[index]);
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
static void bt_settings_scene_start_var_list_enter_callback(void* context, uint32_t index) {
|
||||
furi_assert(context);
|
||||
BtSettingsApp* app = context;
|
||||
if(index == BtSettingIndexForgetDev) {
|
||||
view_dispatcher_send_custom_event(
|
||||
app->view_dispatcher, BtSettingsCustomEventForgetDevices);
|
||||
}
|
||||
}
|
||||
|
||||
void bt_settings_scene_start_on_enter(void* context) {
|
||||
BtSettingsApp* app = context;
|
||||
VariableItemList* var_item_list = app->var_item_list;
|
||||
VariableItem* item;
|
||||
|
||||
if(furi_hal_bt_is_ble_gatt_gap_supported()) {
|
||||
item = variable_item_list_add(
|
||||
var_item_list,
|
||||
"Bluetooth",
|
||||
BtSettingNum,
|
||||
bt_settings_scene_start_var_list_change_callback,
|
||||
app);
|
||||
if(app->settings.enabled) {
|
||||
variable_item_set_current_value_index(item, BtSettingOn);
|
||||
variable_item_set_current_value_text(item, bt_settings_text[BtSettingOn]);
|
||||
} else {
|
||||
variable_item_set_current_value_index(item, BtSettingOff);
|
||||
variable_item_set_current_value_text(item, bt_settings_text[BtSettingOff]);
|
||||
}
|
||||
variable_item_list_add(var_item_list, "Forget All Paired Devices", 1, NULL, NULL);
|
||||
variable_item_list_set_enter_callback(
|
||||
var_item_list, bt_settings_scene_start_var_list_enter_callback, app);
|
||||
} else {
|
||||
item = variable_item_list_add(var_item_list, "Bluetooth", 1, NULL, NULL);
|
||||
variable_item_set_current_value_text(item, "Broken");
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, BtSettingsAppViewVarItemList);
|
||||
}
|
||||
|
||||
bool bt_settings_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
BtSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == BtSettingOn) {
|
||||
furi_hal_bt_start_advertising();
|
||||
app->settings.enabled = true;
|
||||
consumed = true;
|
||||
} else if(event.event == BtSettingOff) {
|
||||
app->settings.enabled = false;
|
||||
furi_hal_bt_stop_advertising();
|
||||
consumed = true;
|
||||
} else if(event.event == BtSettingsCustomEventForgetDevices) {
|
||||
scene_manager_next_scene(app->scene_manager, BtSettingsAppSceneForgetDevConfirm);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void bt_settings_scene_start_on_exit(void* context) {
|
||||
BtSettingsApp* app = context;
|
||||
variable_item_list_reset(app->var_item_list);
|
||||
}
|
||||
12
applications/settings/desktop_settings/application.fam
Normal file
12
applications/settings/desktop_settings/application.fam
Normal file
@@ -0,0 +1,12 @@
|
||||
App(
|
||||
appid="desktop_settings",
|
||||
name="Desktop",
|
||||
apptype=FlipperAppType.SETTINGS,
|
||||
entry_point="desktop_settings_app",
|
||||
requires=[
|
||||
"desktop",
|
||||
"gui",
|
||||
],
|
||||
stack_size=1 * 1024,
|
||||
order=50,
|
||||
)
|
||||
102
applications/settings/desktop_settings/desktop_settings_app.c
Normal file
102
applications/settings/desktop_settings/desktop_settings_app.c
Normal file
@@ -0,0 +1,102 @@
|
||||
#include <furi.h>
|
||||
#include <gui/modules/popup.h>
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
#include "desktop_settings_app.h"
|
||||
#include "scenes/desktop_settings_scene.h"
|
||||
#include <desktop/views/desktop_view_pin_input.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 = malloc(sizeof(DesktopSettingsApp));
|
||||
|
||||
app->gui = furi_record_open(RECORD_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->popup = popup_alloc();
|
||||
app->submenu = submenu_alloc();
|
||||
app->variable_item_list = variable_item_list_alloc();
|
||||
app->pin_input_view = desktop_view_pin_input_alloc();
|
||||
app->pin_setup_howto_view = desktop_settings_view_pin_setup_howto_alloc();
|
||||
app->pin_setup_howto2_view = desktop_settings_view_pin_setup_howto2_alloc();
|
||||
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, DesktopSettingsAppViewMenu, submenu_get_view(app->submenu));
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
DesktopSettingsAppViewVarItemList,
|
||||
variable_item_list_get_view(app->variable_item_list));
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, DesktopSettingsAppViewIdPopup, popup_get_view(app->popup));
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
DesktopSettingsAppViewIdPinInput,
|
||||
desktop_view_pin_input_get_view(app->pin_input_view));
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
DesktopSettingsAppViewIdPinSetupHowto,
|
||||
desktop_settings_view_pin_setup_howto_get_view(app->pin_setup_howto_view));
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
DesktopSettingsAppViewIdPinSetupHowto2,
|
||||
desktop_settings_view_pin_setup_howto2_get_view(app->pin_setup_howto2_view));
|
||||
return app;
|
||||
}
|
||||
|
||||
void desktop_settings_app_free(DesktopSettingsApp* app) {
|
||||
furi_assert(app);
|
||||
// Variable item list
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewMenu);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewVarItemList);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPopup);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinInput);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto2);
|
||||
variable_item_list_free(app->variable_item_list);
|
||||
submenu_free(app->submenu);
|
||||
popup_free(app->popup);
|
||||
desktop_view_pin_input_free(app->pin_input_view);
|
||||
desktop_settings_view_pin_setup_howto_free(app->pin_setup_howto_view);
|
||||
desktop_settings_view_pin_setup_howto2_free(app->pin_setup_howto2_view);
|
||||
// View dispatcher
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
scene_manager_free(app->scene_manager);
|
||||
// Records
|
||||
furi_record_close(RECORD_GUI);
|
||||
free(app);
|
||||
}
|
||||
|
||||
extern int32_t desktop_settings_app(void* p) {
|
||||
DesktopSettingsApp* app = desktop_settings_app_alloc();
|
||||
LOAD_DESKTOP_SETTINGS(&app->settings);
|
||||
if(p && (strcmp(p, DESKTOP_SETTINGS_RUN_PIN_SETUP_ARG) == 0)) {
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto);
|
||||
} else {
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneStart);
|
||||
}
|
||||
|
||||
view_dispatcher_run(app->view_dispatcher);
|
||||
desktop_settings_app_free(app);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <gui/modules/popup.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
|
||||
#include <desktop/desktop_settings.h>
|
||||
#include <desktop/views/desktop_view_pin_input.h>
|
||||
#include "views/desktop_settings_view_pin_setup_howto.h"
|
||||
#include "views/desktop_settings_view_pin_setup_howto2.h"
|
||||
|
||||
typedef enum {
|
||||
DesktopSettingsAppViewMenu,
|
||||
DesktopSettingsAppViewVarItemList,
|
||||
DesktopSettingsAppViewIdPopup,
|
||||
DesktopSettingsAppViewIdPinInput,
|
||||
DesktopSettingsAppViewIdPinSetupHowto,
|
||||
DesktopSettingsAppViewIdPinSetupHowto2,
|
||||
} DesktopSettingsAppView;
|
||||
|
||||
typedef struct {
|
||||
DesktopSettings settings;
|
||||
|
||||
Gui* gui;
|
||||
SceneManager* scene_manager;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
VariableItemList* variable_item_list;
|
||||
Submenu* submenu;
|
||||
Popup* popup;
|
||||
DesktopViewPinInput* pin_input_view;
|
||||
DesktopSettingsViewPinSetupHowto* pin_setup_howto_view;
|
||||
DesktopSettingsViewPinSetupHowto2* pin_setup_howto2_view;
|
||||
|
||||
PinCode pincode_buffer;
|
||||
bool pincode_buffer_filled;
|
||||
|
||||
uint8_t menu_idx;
|
||||
} DesktopSettingsApp;
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "desktop_settings_scene.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const desktop_settings_on_enter_handlers[])(void*) = {
|
||||
#include "desktop_settings_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_event,
|
||||
bool (*const desktop_settings_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "desktop_settings_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_exit,
|
||||
void (*const desktop_settings_on_exit_handlers[])(void* context) = {
|
||||
#include "desktop_settings_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers desktop_settings_scene_handlers = {
|
||||
.on_enter_handlers = desktop_settings_on_enter_handlers,
|
||||
.on_event_handlers = desktop_settings_on_event_handlers,
|
||||
.on_exit_handlers = desktop_settings_on_exit_handlers,
|
||||
.scene_num = DesktopSettingsAppSceneNum,
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) DesktopSettingsAppScene##id,
|
||||
typedef enum {
|
||||
#include "desktop_settings_scene_config.h"
|
||||
DesktopSettingsAppSceneNum,
|
||||
} DesktopSettingsAppScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers desktop_settings_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "desktop_settings_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_event handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) \
|
||||
bool prefix##_scene_##name##_on_event(void* context, SceneManagerEvent event);
|
||||
#include "desktop_settings_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Generate scene on_exit handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_exit(void* context);
|
||||
#include "desktop_settings_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
@@ -0,0 +1,11 @@
|
||||
ADD_SCENE(desktop_settings, start, Start)
|
||||
ADD_SCENE(desktop_settings, favorite, Favorite)
|
||||
ADD_SCENE(desktop_settings, pin_menu, PinMenu)
|
||||
|
||||
ADD_SCENE(desktop_settings, pin_auth, PinAuth)
|
||||
ADD_SCENE(desktop_settings, pin_error, PinError)
|
||||
ADD_SCENE(desktop_settings, pin_disable, PinDisable)
|
||||
ADD_SCENE(desktop_settings, pin_setup, PinSetup)
|
||||
ADD_SCENE(desktop_settings, pin_setup_howto, PinSetupHowto)
|
||||
ADD_SCENE(desktop_settings, pin_setup_howto2, PinSetupHowto2)
|
||||
ADD_SCENE(desktop_settings, pin_setup_done, PinSetupDone)
|
||||
@@ -0,0 +1,61 @@
|
||||
#include "../desktop_settings_app.h"
|
||||
#include "applications.h"
|
||||
#include "desktop_settings_scene.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_reset(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);
|
||||
}
|
||||
|
||||
uint32_t primary_favorite =
|
||||
scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite);
|
||||
|
||||
submenu_set_header(
|
||||
app->submenu, primary_favorite ? "Primary favorite app:" : "Secondary favorite app:");
|
||||
|
||||
if(primary_favorite) {
|
||||
submenu_set_selected_item(app->submenu, app->settings.favorite_primary);
|
||||
} else {
|
||||
submenu_set_selected_item(app->submenu, app->settings.favorite_secondary);
|
||||
}
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewMenu);
|
||||
}
|
||||
|
||||
bool desktop_settings_scene_favorite_on_event(void* context, SceneManagerEvent event) {
|
||||
DesktopSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
uint32_t primary_favorite =
|
||||
scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite);
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(primary_favorite) {
|
||||
app->settings.favorite_primary = event.event;
|
||||
} else {
|
||||
app->settings.favorite_secondary = event.event;
|
||||
}
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
consumed = true;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_scene_favorite_on_exit(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
SAVE_DESKTOP_SETTINGS(&app->settings);
|
||||
submenu_reset(app->submenu);
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#define SCENE_STATE_PIN_AUTH_DISABLE (0)
|
||||
#define SCENE_STATE_PIN_AUTH_CHANGE_PIN (1)
|
||||
|
||||
#define SCENE_STATE_PIN_ERROR_MISMATCH (0)
|
||||
#define SCENE_STATE_PIN_ERROR_WRONG (1)
|
||||
@@ -0,0 +1,95 @@
|
||||
#include <stdint.h>
|
||||
#include <core/check.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <desktop/helpers/pin_lock.h>
|
||||
#include "../desktop_settings_app.h"
|
||||
#include <desktop/desktop_settings.h>
|
||||
#include <desktop/views/desktop_view_pin_input.h>
|
||||
#include "desktop_settings_scene.h"
|
||||
#include "desktop_settings_scene_i.h"
|
||||
|
||||
#define SCENE_EVENT_EXIT (0U)
|
||||
#define SCENE_EVENT_PINS_EQUAL (1U)
|
||||
#define SCENE_EVENT_PINS_DIFFERENT (2U)
|
||||
|
||||
static void pin_auth_done_callback(const PinCode* pin_code, void* context) {
|
||||
furi_assert(pin_code);
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
|
||||
app->pincode_buffer = *pin_code;
|
||||
if(desktop_pins_are_equal(&app->settings.pin_code, pin_code)) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_EQUAL);
|
||||
} else {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_DIFFERENT);
|
||||
}
|
||||
}
|
||||
|
||||
static void pin_auth_back_callback(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_EXIT);
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_auth_on_enter(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
|
||||
LOAD_DESKTOP_SETTINGS(&app->settings);
|
||||
furi_assert(app->settings.pin_code.length > 0);
|
||||
|
||||
desktop_view_pin_input_set_context(app->pin_input_view, app);
|
||||
desktop_view_pin_input_set_back_callback(app->pin_input_view, pin_auth_back_callback);
|
||||
desktop_view_pin_input_set_done_callback(app->pin_input_view, pin_auth_done_callback);
|
||||
desktop_view_pin_input_set_label_button(app->pin_input_view, "OK");
|
||||
desktop_view_pin_input_set_label_primary(app->pin_input_view, 0, 0, NULL);
|
||||
desktop_view_pin_input_set_label_secondary(
|
||||
app->pin_input_view, 0, 8, "Enter your current PIN:");
|
||||
desktop_view_pin_input_reset_pin(app->pin_input_view);
|
||||
desktop_view_pin_input_unlock_input(app->pin_input_view);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPinInput);
|
||||
}
|
||||
|
||||
bool desktop_settings_scene_pin_auth_on_event(void* context, SceneManagerEvent event) {
|
||||
DesktopSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SCENE_EVENT_PINS_DIFFERENT:
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, DesktopSettingsAppScenePinError, SCENE_STATE_PIN_ERROR_WRONG);
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinError);
|
||||
consumed = true;
|
||||
break;
|
||||
case SCENE_EVENT_PINS_EQUAL: {
|
||||
uint32_t state =
|
||||
scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppScenePinAuth);
|
||||
if(state == SCENE_STATE_PIN_AUTH_CHANGE_PIN) {
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto);
|
||||
} else if(state == SCENE_STATE_PIN_AUTH_DISABLE) {
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinDisable);
|
||||
} else {
|
||||
furi_assert(0);
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
case SCENE_EVENT_EXIT:
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, DesktopSettingsAppScenePinMenu);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_auth_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
desktop_view_pin_input_set_back_callback(app->pin_input_view, NULL);
|
||||
desktop_view_pin_input_set_done_callback(app->pin_input_view, NULL);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
#include <stdint.h>
|
||||
#include <core/check.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/modules/popup.h>
|
||||
|
||||
#include "../desktop_settings_app.h"
|
||||
#include <desktop/desktop_settings.h>
|
||||
#include "desktop_settings_scene.h"
|
||||
|
||||
#define SCENE_EVENT_EXIT (0U)
|
||||
|
||||
static void pin_disable_back_callback(void* context) {
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_EXIT);
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_disable_on_enter(void* context) {
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
app->settings.pin_code.length = 0;
|
||||
memset(app->settings.pin_code.data, '0', sizeof(app->settings.pin_code.data));
|
||||
SAVE_DESKTOP_SETTINGS(&app->settings);
|
||||
|
||||
popup_set_context(app->popup, app);
|
||||
popup_set_callback(app->popup, pin_disable_back_callback);
|
||||
popup_set_icon(app->popup, 0, 2, &I_DolphinMafia_115x62);
|
||||
popup_set_header(app->popup, "PIN\ndeleted!", 95, 9, AlignCenter, AlignCenter);
|
||||
popup_set_timeout(app->popup, 1500);
|
||||
popup_enable_timeout(app->popup);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPopup);
|
||||
}
|
||||
|
||||
bool desktop_settings_scene_pin_disable_on_event(void* context, SceneManagerEvent event) {
|
||||
DesktopSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SCENE_EVENT_EXIT:
|
||||
scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, DesktopSettingsAppScenePinMenu);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_disable_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
#include <stdint.h>
|
||||
#include <core/check.h>
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
#include <desktop/desktop_settings.h>
|
||||
#include <desktop/views/desktop_view_pin_input.h>
|
||||
#include "desktop_settings_scene.h"
|
||||
#include "desktop_settings_scene_i.h"
|
||||
#include <desktop/helpers/pin_lock.h>
|
||||
#include "../desktop_settings_app.h"
|
||||
|
||||
#define SCENE_EVENT_EXIT (0U)
|
||||
|
||||
static void pin_error_back_callback(void* context) {
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_EXIT);
|
||||
}
|
||||
|
||||
static void pin_error_done_callback(const PinCode* pin_code, void* context) {
|
||||
UNUSED(pin_code);
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_EXIT);
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_error_on_enter(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
desktop_pin_lock_error_notify();
|
||||
|
||||
desktop_view_pin_input_set_context(app->pin_input_view, app);
|
||||
desktop_view_pin_input_set_back_callback(app->pin_input_view, pin_error_back_callback);
|
||||
desktop_view_pin_input_set_done_callback(app->pin_input_view, pin_error_done_callback);
|
||||
|
||||
uint32_t state =
|
||||
scene_manager_get_scene_state(app->scene_manager, DesktopSettingsAppScenePinError);
|
||||
if(state == SCENE_STATE_PIN_ERROR_MISMATCH) {
|
||||
desktop_view_pin_input_set_label_primary(app->pin_input_view, 29, 8, "PIN mismatch!");
|
||||
} else if(state == SCENE_STATE_PIN_ERROR_WRONG) {
|
||||
desktop_view_pin_input_set_label_primary(app->pin_input_view, 35, 8, "Wrong PIN!");
|
||||
} else {
|
||||
furi_assert(0);
|
||||
}
|
||||
desktop_view_pin_input_set_label_secondary(app->pin_input_view, 0, 8, NULL);
|
||||
desktop_view_pin_input_set_label_button(app->pin_input_view, "Retry");
|
||||
desktop_view_pin_input_lock_input(app->pin_input_view);
|
||||
desktop_view_pin_input_set_pin(app->pin_input_view, &app->pincode_buffer);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPinInput);
|
||||
}
|
||||
|
||||
bool desktop_settings_scene_pin_error_on_event(void* context, SceneManagerEvent event) {
|
||||
DesktopSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SCENE_EVENT_EXIT:
|
||||
scene_manager_previous_scene(app->scene_manager);
|
||||
consumed = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_error_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
desktop_view_pin_input_unlock_input(app->pin_input_view);
|
||||
desktop_view_pin_input_set_back_callback(app->pin_input_view, NULL);
|
||||
desktop_view_pin_input_set_done_callback(app->pin_input_view, NULL);
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
#include <gui/scene_manager.h>
|
||||
#include <applications.h>
|
||||
|
||||
#include "../desktop_settings_app.h"
|
||||
#include "desktop_settings_scene.h"
|
||||
#include "desktop_settings_scene_i.h"
|
||||
|
||||
#define SCENE_EVENT_SET_PIN 0
|
||||
#define SCENE_EVENT_CHANGE_PIN 1
|
||||
#define SCENE_EVENT_DISABLE_PIN 2
|
||||
|
||||
static void desktop_settings_scene_pin_menu_submenu_callback(void* context, uint32_t index) {
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_menu_on_enter(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
Submenu* submenu = app->submenu;
|
||||
submenu_reset(submenu);
|
||||
|
||||
if(!app->settings.pin_code.length) {
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Set Pin",
|
||||
SCENE_EVENT_SET_PIN,
|
||||
desktop_settings_scene_pin_menu_submenu_callback,
|
||||
app);
|
||||
|
||||
} else {
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Change Pin",
|
||||
SCENE_EVENT_CHANGE_PIN,
|
||||
desktop_settings_scene_pin_menu_submenu_callback,
|
||||
app);
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Disable",
|
||||
SCENE_EVENT_DISABLE_PIN,
|
||||
desktop_settings_scene_pin_menu_submenu_callback,
|
||||
app);
|
||||
}
|
||||
|
||||
submenu_set_header(app->submenu, "Pin code settings:");
|
||||
submenu_set_selected_item(app->submenu, app->menu_idx);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewMenu);
|
||||
}
|
||||
|
||||
bool desktop_settings_scene_pin_menu_on_event(void* context, SceneManagerEvent event) {
|
||||
DesktopSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SCENE_EVENT_SET_PIN:
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto);
|
||||
consumed = true;
|
||||
break;
|
||||
case SCENE_EVENT_CHANGE_PIN:
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager,
|
||||
DesktopSettingsAppScenePinAuth,
|
||||
SCENE_STATE_PIN_AUTH_CHANGE_PIN);
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinAuth);
|
||||
consumed = true;
|
||||
break;
|
||||
case SCENE_EVENT_DISABLE_PIN:
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, DesktopSettingsAppScenePinAuth, SCENE_STATE_PIN_AUTH_DISABLE);
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinAuth);
|
||||
consumed = true;
|
||||
break;
|
||||
default:
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_menu_on_exit(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
submenu_reset(app->submenu);
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
#include <stdint.h>
|
||||
#include <core/check.h>
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
#include "../desktop_settings_app.h"
|
||||
#include <desktop/desktop_settings.h>
|
||||
#include <desktop/views/desktop_view_pin_input.h>
|
||||
#include "desktop_settings_scene.h"
|
||||
#include "desktop_settings_scene_i.h"
|
||||
#include <desktop/helpers/pin_lock.h>
|
||||
|
||||
#define SCENE_EVENT_EXIT (0U)
|
||||
#define SCENE_EVENT_1ST_PIN_ENTERED (1U)
|
||||
#define SCENE_EVENT_PINS_EQUAL (2U)
|
||||
#define SCENE_EVENT_PINS_DIFFERENT (3U)
|
||||
|
||||
static void pin_setup_done_callback(const PinCode* pin_code, void* context) {
|
||||
furi_assert(pin_code);
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
|
||||
if(!app->pincode_buffer_filled) {
|
||||
app->pincode_buffer = *pin_code;
|
||||
app->pincode_buffer_filled = true;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_1ST_PIN_ENTERED);
|
||||
} else {
|
||||
app->pincode_buffer_filled = false;
|
||||
if(desktop_pins_are_equal(&app->pincode_buffer, pin_code)) {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_EQUAL);
|
||||
} else {
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_PINS_DIFFERENT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void pin_setup_back_callback(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_EXIT);
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_setup_on_enter(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
|
||||
app->pincode_buffer_filled = false;
|
||||
desktop_view_pin_input_set_context(app->pin_input_view, app);
|
||||
desktop_view_pin_input_set_back_callback(app->pin_input_view, pin_setup_back_callback);
|
||||
desktop_view_pin_input_set_done_callback(app->pin_input_view, pin_setup_done_callback);
|
||||
desktop_view_pin_input_set_label_button(app->pin_input_view, "OK");
|
||||
desktop_view_pin_input_set_label_primary(app->pin_input_view, 0, 0, NULL);
|
||||
desktop_view_pin_input_set_label_secondary(
|
||||
app->pin_input_view, 0, 8, "Enter from 4 to 10 arrows:");
|
||||
desktop_view_pin_input_reset_pin(app->pin_input_view);
|
||||
desktop_view_pin_input_unlock_input(app->pin_input_view);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPinInput);
|
||||
}
|
||||
|
||||
bool desktop_settings_scene_pin_setup_on_event(void* context, SceneManagerEvent event) {
|
||||
DesktopSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SCENE_EVENT_1ST_PIN_ENTERED:
|
||||
desktop_view_pin_input_set_label_button(app->pin_input_view, "OK");
|
||||
desktop_view_pin_input_set_label_primary(app->pin_input_view, 0, 0, NULL);
|
||||
desktop_view_pin_input_set_label_secondary(
|
||||
app->pin_input_view, 0, 8, "Confirm your PIN:");
|
||||
desktop_view_pin_input_reset_pin(app->pin_input_view);
|
||||
desktop_view_pin_input_unlock_input(app->pin_input_view);
|
||||
consumed = true;
|
||||
break;
|
||||
case SCENE_EVENT_PINS_DIFFERENT:
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager,
|
||||
DesktopSettingsAppScenePinError,
|
||||
SCENE_STATE_PIN_ERROR_MISMATCH);
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinError);
|
||||
consumed = true;
|
||||
break;
|
||||
case SCENE_EVENT_PINS_EQUAL:
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupHowto2);
|
||||
consumed = true;
|
||||
break;
|
||||
case SCENE_EVENT_EXIT: {
|
||||
uint32_t scene_found;
|
||||
scene_found = scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, DesktopSettingsAppScenePinMenu);
|
||||
if(!scene_found) {
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_setup_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
desktop_view_pin_input_set_back_callback(app->pin_input_view, NULL);
|
||||
desktop_view_pin_input_set_done_callback(app->pin_input_view, NULL);
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
#include <furi.h>
|
||||
#include <notification/notification.h>
|
||||
#include <notification/notification_messages.h>
|
||||
#include <stdint.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
|
||||
#include "../desktop_settings_app.h"
|
||||
#include <desktop/desktop_settings.h>
|
||||
#include <desktop/views/desktop_view_pin_input.h>
|
||||
#include "desktop_settings_scene.h"
|
||||
|
||||
#define SCENE_EVENT_DONE (0U)
|
||||
|
||||
static void pin_setup_done_callback(const PinCode* pin_code, void* context) {
|
||||
furi_assert(pin_code);
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EVENT_DONE);
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_setup_done_on_enter(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
|
||||
app->settings.pin_code = app->pincode_buffer;
|
||||
SAVE_DESKTOP_SETTINGS(&app->settings);
|
||||
NotificationApp* notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
notification_message(notification, &sequence_single_vibro);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
|
||||
desktop_view_pin_input_set_context(app->pin_input_view, app);
|
||||
desktop_view_pin_input_set_back_callback(app->pin_input_view, NULL);
|
||||
desktop_view_pin_input_set_done_callback(app->pin_input_view, pin_setup_done_callback);
|
||||
desktop_view_pin_input_set_pin(app->pin_input_view, &app->settings.pin_code);
|
||||
desktop_view_pin_input_set_label_button(app->pin_input_view, "Done");
|
||||
desktop_view_pin_input_set_label_primary(app->pin_input_view, 29, 8, "PIN activated!");
|
||||
desktop_view_pin_input_set_label_secondary(
|
||||
app->pin_input_view, 7, 45, "Remember or write it down");
|
||||
desktop_view_pin_input_lock_input(app->pin_input_view);
|
||||
desktop_view_pin_input_set_pin_position(app->pin_input_view, 64, 24);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPinInput);
|
||||
}
|
||||
|
||||
bool desktop_settings_scene_pin_setup_done_on_event(void* context, SceneManagerEvent event) {
|
||||
DesktopSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SCENE_EVENT_DONE: {
|
||||
bool scene_found = false;
|
||||
scene_found = scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, DesktopSettingsAppScenePinMenu);
|
||||
if(!scene_found) {
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed = true;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_setup_done_on_exit(void* context) {
|
||||
furi_assert(context);
|
||||
DesktopSettingsApp* app = context;
|
||||
desktop_view_pin_input_set_pin_position(app->pin_input_view, 64, 32);
|
||||
desktop_view_pin_input_set_back_callback(app->pin_input_view, NULL);
|
||||
desktop_view_pin_input_set_done_callback(app->pin_input_view, NULL);
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
#include <furi.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
|
||||
#include "desktop_settings_scene.h"
|
||||
#include "../desktop_settings_app.h"
|
||||
#include "../views/desktop_settings_view_pin_setup_howto.h"
|
||||
|
||||
#define SCENE_EXIT_EVENT (0U)
|
||||
|
||||
static void desktop_settings_scene_pin_lock_done_callback(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EXIT_EVENT);
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_setup_howto_on_enter(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
|
||||
desktop_settings_view_pin_setup_howto_set_callback(
|
||||
app->pin_setup_howto_view, desktop_settings_scene_pin_lock_done_callback, app);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto);
|
||||
}
|
||||
|
||||
bool desktop_settings_scene_pin_setup_howto_on_event(void* context, SceneManagerEvent event) {
|
||||
DesktopSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SCENE_EXIT_EVENT:
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetup);
|
||||
consumed = true;
|
||||
break;
|
||||
default:
|
||||
furi_assert(0);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_setup_howto_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
#include <furi.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "desktop_settings_scene.h"
|
||||
#include "../desktop_settings_app.h"
|
||||
#include "../views/desktop_settings_view_pin_setup_howto2.h"
|
||||
|
||||
#define SCENE_EXIT_EVENT (0U)
|
||||
#define SCENE_DONE_EVENT (1U)
|
||||
|
||||
static void desktop_settings_scene_pin_setup_howto2_done_callback(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_DONE_EVENT);
|
||||
}
|
||||
|
||||
static void desktop_settings_scene_pin_setup_howto2_exit_callback(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, SCENE_EXIT_EVENT);
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_setup_howto2_on_enter(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
|
||||
desktop_settings_view_pin_setup_howto2_set_context(app->pin_setup_howto2_view, app);
|
||||
desktop_settings_view_pin_setup_howto2_set_ok_callback(
|
||||
app->pin_setup_howto2_view, desktop_settings_scene_pin_setup_howto2_done_callback);
|
||||
desktop_settings_view_pin_setup_howto2_set_cancel_callback(
|
||||
app->pin_setup_howto2_view, desktop_settings_scene_pin_setup_howto2_exit_callback);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewIdPinSetupHowto2);
|
||||
}
|
||||
|
||||
bool desktop_settings_scene_pin_setup_howto2_on_event(void* context, SceneManagerEvent event) {
|
||||
DesktopSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case SCENE_DONE_EVENT: {
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinSetupDone);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
case SCENE_EXIT_EVENT: {
|
||||
bool scene_found = false;
|
||||
scene_found = scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, DesktopSettingsAppScenePinMenu);
|
||||
if(!scene_found) {
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
}
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
furi_assert(0);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_scene_pin_setup_howto2_on_exit(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
desktop_settings_view_pin_setup_howto2_set_ok_callback(app->pin_setup_howto2_view, NULL);
|
||||
desktop_settings_view_pin_setup_howto2_set_cancel_callback(app->pin_setup_howto2_view, NULL);
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
#include <applications.h>
|
||||
#include <lib/toolbox/value_index.h>
|
||||
|
||||
#include "../desktop_settings_app.h"
|
||||
#include "desktop_settings_scene.h"
|
||||
|
||||
#define SCENE_EVENT_SELECT_FAVORITE_PRIMARY 0
|
||||
#define SCENE_EVENT_SELECT_FAVORITE_SECONDARY 1
|
||||
#define SCENE_EVENT_SELECT_PIN_SETUP 2
|
||||
#define SCENE_EVENT_SELECT_AUTO_LOCK_DELAY 3
|
||||
|
||||
#define AUTO_LOCK_DELAY_COUNT 6
|
||||
const char* const auto_lock_delay_text[AUTO_LOCK_DELAY_COUNT] = {
|
||||
"OFF",
|
||||
"30s",
|
||||
"60s",
|
||||
"2min",
|
||||
"5min",
|
||||
"10min",
|
||||
};
|
||||
|
||||
const uint32_t auto_lock_delay_value[AUTO_LOCK_DELAY_COUNT] =
|
||||
{0, 30000, 60000, 120000, 300000, 600000};
|
||||
|
||||
static void desktop_settings_scene_start_var_list_enter_callback(void* context, uint32_t index) {
|
||||
DesktopSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
static void desktop_settings_scene_start_auto_lock_delay_changed(VariableItem* item) {
|
||||
DesktopSettingsApp* app = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
variable_item_set_current_value_text(item, auto_lock_delay_text[index]);
|
||||
app->settings.auto_lock_delay_ms = auto_lock_delay_value[index];
|
||||
}
|
||||
|
||||
void desktop_settings_scene_start_on_enter(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
VariableItemList* variable_item_list = app->variable_item_list;
|
||||
|
||||
VariableItem* item;
|
||||
uint8_t value_index;
|
||||
|
||||
variable_item_list_add(variable_item_list, "Primary Favorite App", 1, NULL, NULL);
|
||||
|
||||
variable_item_list_add(variable_item_list, "Secondary Favorite App", 1, NULL, NULL);
|
||||
|
||||
variable_item_list_add(variable_item_list, "PIN Setup", 1, NULL, NULL);
|
||||
|
||||
item = variable_item_list_add(
|
||||
variable_item_list,
|
||||
"Auto Lock Time",
|
||||
AUTO_LOCK_DELAY_COUNT,
|
||||
desktop_settings_scene_start_auto_lock_delay_changed,
|
||||
app);
|
||||
|
||||
variable_item_list_set_enter_callback(
|
||||
variable_item_list, desktop_settings_scene_start_var_list_enter_callback, app);
|
||||
value_index = value_index_uint32(
|
||||
app->settings.auto_lock_delay_ms, auto_lock_delay_value, AUTO_LOCK_DELAY_COUNT);
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, auto_lock_delay_text[value_index]);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, DesktopSettingsAppViewVarItemList);
|
||||
}
|
||||
|
||||
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 SCENE_EVENT_SELECT_FAVORITE_PRIMARY:
|
||||
scene_manager_set_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite, 1);
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneFavorite);
|
||||
consumed = true;
|
||||
break;
|
||||
case SCENE_EVENT_SELECT_FAVORITE_SECONDARY:
|
||||
scene_manager_set_scene_state(app->scene_manager, DesktopSettingsAppSceneFavorite, 0);
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppSceneFavorite);
|
||||
consumed = true;
|
||||
break;
|
||||
case SCENE_EVENT_SELECT_PIN_SETUP:
|
||||
scene_manager_next_scene(app->scene_manager, DesktopSettingsAppScenePinMenu);
|
||||
consumed = true;
|
||||
break;
|
||||
case SCENE_EVENT_SELECT_AUTO_LOCK_DELAY:
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_scene_start_on_exit(void* context) {
|
||||
DesktopSettingsApp* app = context;
|
||||
variable_item_list_reset(app->variable_item_list);
|
||||
SAVE_DESKTOP_SETTINGS(&app->settings);
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/elements.h>
|
||||
#include <gui/canvas.h>
|
||||
#include <toolbox/version.h>
|
||||
#include <assets_icons.h>
|
||||
#include <dolphin/helpers/dolphin_state.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#include "desktop_settings_view_pin_setup_howto.h"
|
||||
|
||||
struct DesktopSettingsViewPinSetupHowto {
|
||||
View* view;
|
||||
DesktopSettingsViewPinSetupHowtoDoneCallback callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
static void desktop_settings_view_pin_setup_howto_draw(Canvas* canvas, void* model) {
|
||||
furi_assert(canvas);
|
||||
furi_assert(model);
|
||||
|
||||
canvas_draw_icon(canvas, 16, 18, &I_Pin_attention_dpad_29x29);
|
||||
elements_button_right(canvas, "Next");
|
||||
|
||||
canvas_set_font(canvas, FontPrimary);
|
||||
elements_multiline_text_aligned(canvas, 64, 0, AlignCenter, AlignTop, "Setting up PIN");
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_multiline_text(canvas, 58, 24, "Prepare to use\narrows as\nPIN symbols");
|
||||
}
|
||||
|
||||
static bool desktop_settings_view_pin_setup_howto_input(InputEvent* event, void* context) {
|
||||
furi_assert(event);
|
||||
furi_assert(context);
|
||||
|
||||
DesktopSettingsViewPinSetupHowto* instance = context;
|
||||
bool consumed = false;
|
||||
|
||||
if((event->key == InputKeyRight) && (event->type == InputTypeShort)) {
|
||||
instance->callback(instance->context);
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_view_pin_setup_howto_set_callback(
|
||||
DesktopSettingsViewPinSetupHowto* instance,
|
||||
DesktopSettingsViewPinSetupHowtoDoneCallback callback,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
furi_assert(callback);
|
||||
instance->callback = callback;
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
DesktopSettingsViewPinSetupHowto* desktop_settings_view_pin_setup_howto_alloc() {
|
||||
DesktopSettingsViewPinSetupHowto* view = malloc(sizeof(DesktopSettingsViewPinSetupHowto));
|
||||
view->view = view_alloc();
|
||||
view_allocate_model(view->view, ViewModelTypeLockFree, 1);
|
||||
view_set_context(view->view, view);
|
||||
view_set_draw_callback(view->view, desktop_settings_view_pin_setup_howto_draw);
|
||||
view_set_input_callback(view->view, desktop_settings_view_pin_setup_howto_input);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
void desktop_settings_view_pin_setup_howto_free(DesktopSettingsViewPinSetupHowto* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
view_free(instance->view);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
View* desktop_settings_view_pin_setup_howto_get_view(DesktopSettingsViewPinSetupHowto* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->view;
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct DesktopSettingsViewPinSetupHowto DesktopSettingsViewPinSetupHowto;
|
||||
|
||||
typedef void (*DesktopSettingsViewPinSetupHowtoDoneCallback)(void*);
|
||||
|
||||
void desktop_settings_view_pin_setup_howto_set_callback(
|
||||
DesktopSettingsViewPinSetupHowto* instance,
|
||||
DesktopSettingsViewPinSetupHowtoDoneCallback callback,
|
||||
void* context);
|
||||
DesktopSettingsViewPinSetupHowto* desktop_settings_view_pin_setup_howto_alloc();
|
||||
void desktop_settings_view_pin_setup_howto_free(DesktopSettingsViewPinSetupHowto* instance);
|
||||
View* desktop_settings_view_pin_setup_howto_get_view(DesktopSettingsViewPinSetupHowto* instance);
|
||||
@@ -0,0 +1,100 @@
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
#include <gui/elements.h>
|
||||
#include <gui/canvas.h>
|
||||
#include <toolbox/version.h>
|
||||
#include <assets_icons.h>
|
||||
#include <dolphin/helpers/dolphin_state.h>
|
||||
#include <dolphin/dolphin.h>
|
||||
|
||||
#include "desktop_settings_view_pin_setup_howto2.h"
|
||||
|
||||
struct DesktopSettingsViewPinSetupHowto2 {
|
||||
View* view;
|
||||
DesktopSettingsViewPinSetupHowto2Callback cancel_callback;
|
||||
DesktopSettingsViewPinSetupHowto2Callback ok_callback;
|
||||
void* context;
|
||||
};
|
||||
|
||||
static void desktop_settings_view_pin_setup_howto2_draw(Canvas* canvas, void* model) {
|
||||
furi_assert(canvas);
|
||||
furi_assert(model);
|
||||
|
||||
canvas_set_font(canvas, FontSecondary);
|
||||
elements_multiline_text_aligned(
|
||||
canvas,
|
||||
64,
|
||||
24,
|
||||
AlignCenter,
|
||||
AlignCenter,
|
||||
"Forgotten PIN can only be\n"
|
||||
"reset with entire device.\n"
|
||||
"Read docs How to reset PIN.");
|
||||
|
||||
elements_button_right(canvas, "OK");
|
||||
elements_button_left(canvas, "Cancel");
|
||||
}
|
||||
|
||||
static bool desktop_settings_view_pin_setup_howto2_input(InputEvent* event, void* context) {
|
||||
furi_assert(event);
|
||||
furi_assert(context);
|
||||
|
||||
DesktopSettingsViewPinSetupHowto2* instance = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event->type == InputTypeShort) {
|
||||
if(event->key == InputKeyRight) {
|
||||
instance->ok_callback(instance->context);
|
||||
consumed = true;
|
||||
} else if(event->key == InputKeyLeft) {
|
||||
instance->cancel_callback(instance->context);
|
||||
consumed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void desktop_settings_view_pin_setup_howto2_set_context(
|
||||
DesktopSettingsViewPinSetupHowto2* instance,
|
||||
void* context) {
|
||||
furi_assert(instance);
|
||||
instance->context = context;
|
||||
}
|
||||
|
||||
void desktop_settings_view_pin_setup_howto2_set_cancel_callback(
|
||||
DesktopSettingsViewPinSetupHowto2* instance,
|
||||
DesktopSettingsViewPinSetupHowto2Callback callback) {
|
||||
furi_assert(instance);
|
||||
instance->cancel_callback = callback;
|
||||
}
|
||||
|
||||
void desktop_settings_view_pin_setup_howto2_set_ok_callback(
|
||||
DesktopSettingsViewPinSetupHowto2* instance,
|
||||
DesktopSettingsViewPinSetupHowto2Callback callback) {
|
||||
furi_assert(instance);
|
||||
instance->ok_callback = callback;
|
||||
}
|
||||
|
||||
DesktopSettingsViewPinSetupHowto2* desktop_settings_view_pin_setup_howto2_alloc() {
|
||||
DesktopSettingsViewPinSetupHowto2* view = malloc(sizeof(DesktopSettingsViewPinSetupHowto2));
|
||||
view->view = view_alloc();
|
||||
view_allocate_model(view->view, ViewModelTypeLockFree, 1);
|
||||
view_set_context(view->view, view);
|
||||
view_set_draw_callback(view->view, desktop_settings_view_pin_setup_howto2_draw);
|
||||
view_set_input_callback(view->view, desktop_settings_view_pin_setup_howto2_input);
|
||||
|
||||
return view;
|
||||
}
|
||||
|
||||
void desktop_settings_view_pin_setup_howto2_free(DesktopSettingsViewPinSetupHowto2* instance) {
|
||||
furi_assert(instance);
|
||||
|
||||
view_free(instance->view);
|
||||
free(instance);
|
||||
}
|
||||
|
||||
View* desktop_settings_view_pin_setup_howto2_get_view(DesktopSettingsViewPinSetupHowto2* instance) {
|
||||
furi_assert(instance);
|
||||
return instance->view;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct DesktopSettingsViewPinSetupHowto2 DesktopSettingsViewPinSetupHowto2;
|
||||
|
||||
typedef void (*DesktopSettingsViewPinSetupHowto2Callback)(void*);
|
||||
|
||||
DesktopSettingsViewPinSetupHowto2* desktop_settings_view_pin_setup_howto2_alloc();
|
||||
void desktop_settings_view_pin_setup_howto2_free(DesktopSettingsViewPinSetupHowto2* instance);
|
||||
View* desktop_settings_view_pin_setup_howto2_get_view(DesktopSettingsViewPinSetupHowto2* instance);
|
||||
void desktop_settings_view_pin_setup_howto2_set_context(
|
||||
DesktopSettingsViewPinSetupHowto2* instance,
|
||||
void* context);
|
||||
void desktop_settings_view_pin_setup_howto2_set_cancel_callback(
|
||||
DesktopSettingsViewPinSetupHowto2* instance,
|
||||
DesktopSettingsViewPinSetupHowto2Callback callback);
|
||||
void desktop_settings_view_pin_setup_howto2_set_ok_callback(
|
||||
DesktopSettingsViewPinSetupHowto2* instance,
|
||||
DesktopSettingsViewPinSetupHowto2Callback callback);
|
||||
13
applications/settings/dolphin_passport/application.fam
Normal file
13
applications/settings/dolphin_passport/application.fam
Normal file
@@ -0,0 +1,13 @@
|
||||
App(
|
||||
appid="passport",
|
||||
name="Passport",
|
||||
apptype=FlipperAppType.SETTINGS,
|
||||
entry_point="passport_app",
|
||||
cdefines=["APP_PASSPORT"],
|
||||
requires=[
|
||||
"gui",
|
||||
"dolphin",
|
||||
],
|
||||
stack_size=1 * 1024,
|
||||
order=60,
|
||||
)
|
||||
115
applications/settings/dolphin_passport/passport.c
Normal file
115
applications/settings/dolphin_passport/passport.c
Normal file
@@ -0,0 +1,115 @@
|
||||
#include "assets_icons.h"
|
||||
#include "dolphin/helpers/dolphin_state.h"
|
||||
#include <core/check.h>
|
||||
#include <core/record.h>
|
||||
#include <furi.h>
|
||||
#include <gui/gui.h>
|
||||
#include <furi_hal_version.h>
|
||||
#include "dolphin/dolphin.h"
|
||||
#include "math.h"
|
||||
|
||||
#define MOODS_TOTAL 3
|
||||
#define BUTTHURT_MAX 3
|
||||
|
||||
static const Icon* const portrait_happy[BUTTHURT_MAX] = {
|
||||
&I_passport_happy1_46x49,
|
||||
&I_passport_happy2_46x49,
|
||||
&I_passport_happy3_46x49};
|
||||
static const Icon* const portrait_ok[BUTTHURT_MAX] = {
|
||||
&I_passport_okay1_46x49,
|
||||
&I_passport_okay2_46x49,
|
||||
&I_passport_okay3_46x49};
|
||||
static const Icon* const portrait_bad[BUTTHURT_MAX] = {
|
||||
&I_passport_bad1_46x49,
|
||||
&I_passport_bad2_46x49,
|
||||
&I_passport_bad3_46x49};
|
||||
|
||||
static const Icon* const* portraits[MOODS_TOTAL] = {portrait_happy, portrait_ok, portrait_bad};
|
||||
|
||||
static void input_callback(InputEvent* input, void* ctx) {
|
||||
FuriSemaphore* semaphore = ctx;
|
||||
|
||||
if((input->type == InputTypeShort) && (input->key == InputKeyBack)) {
|
||||
furi_semaphore_release(semaphore);
|
||||
}
|
||||
}
|
||||
|
||||
static void render_callback(Canvas* canvas, void* ctx) {
|
||||
DolphinStats* stats = ctx;
|
||||
|
||||
char level_str[20];
|
||||
char mood_str[32];
|
||||
uint8_t mood = 0;
|
||||
|
||||
if(stats->butthurt <= 4) {
|
||||
mood = 0;
|
||||
snprintf(mood_str, 20, "Mood: Happy");
|
||||
} else if(stats->butthurt <= 9) {
|
||||
mood = 1;
|
||||
snprintf(mood_str, 20, "Mood: Ok");
|
||||
} else {
|
||||
mood = 2;
|
||||
snprintf(mood_str, 20, "Mood: Angry");
|
||||
}
|
||||
|
||||
uint32_t xp_progress = 0;
|
||||
uint32_t xp_to_levelup = dolphin_state_xp_to_levelup(stats->icounter);
|
||||
uint32_t xp_for_current_level =
|
||||
xp_to_levelup + dolphin_state_xp_above_last_levelup(stats->icounter);
|
||||
if(stats->level == 3) {
|
||||
xp_progress = 0;
|
||||
} else {
|
||||
xp_progress = xp_to_levelup * 64 / xp_for_current_level;
|
||||
}
|
||||
|
||||
// multipass
|
||||
canvas_draw_icon(canvas, 0, 0, &I_passport_left_6x46);
|
||||
canvas_draw_icon(canvas, 0, 46, &I_passport_bottom_128x18);
|
||||
canvas_draw_line(canvas, 6, 0, 125, 0);
|
||||
canvas_draw_line(canvas, 127, 2, 127, 47);
|
||||
canvas_draw_dot(canvas, 126, 1);
|
||||
|
||||
// portrait
|
||||
furi_assert((stats->level > 0) && (stats->level <= 3));
|
||||
canvas_draw_icon(canvas, 9, 5, portraits[mood][stats->level - 1]);
|
||||
canvas_draw_line(canvas, 58, 16, 123, 16);
|
||||
canvas_draw_line(canvas, 58, 30, 123, 30);
|
||||
canvas_draw_line(canvas, 58, 44, 123, 44);
|
||||
|
||||
const char* my_name = furi_hal_version_get_name_ptr();
|
||||
snprintf(level_str, 20, "Level: %hu", stats->level);
|
||||
canvas_draw_str(canvas, 58, 12, my_name ? my_name : "Unknown");
|
||||
canvas_draw_str(canvas, 58, 26, mood_str);
|
||||
canvas_draw_str(canvas, 58, 40, level_str);
|
||||
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
canvas_draw_box(canvas, 123 - xp_progress, 47, xp_progress + 1, 6);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_draw_line(canvas, 123, 47, 123, 52);
|
||||
}
|
||||
|
||||
int32_t passport_app(void* p) {
|
||||
UNUSED(p);
|
||||
FuriSemaphore* semaphore = furi_semaphore_alloc(1, 0);
|
||||
furi_assert(semaphore);
|
||||
|
||||
ViewPort* view_port = view_port_alloc();
|
||||
|
||||
Dolphin* dolphin = furi_record_open(RECORD_DOLPHIN);
|
||||
DolphinStats stats = dolphin_stats(dolphin);
|
||||
furi_record_close(RECORD_DOLPHIN);
|
||||
view_port_draw_callback_set(view_port, render_callback, &stats);
|
||||
view_port_input_callback_set(view_port, input_callback, semaphore);
|
||||
Gui* gui = furi_record_open(RECORD_GUI);
|
||||
gui_add_view_port(gui, view_port, GuiLayerFullscreen);
|
||||
view_port_update(view_port);
|
||||
|
||||
furi_check(furi_semaphore_acquire(semaphore, FuriWaitForever) == FuriStatusOk);
|
||||
|
||||
gui_remove_view_port(gui, view_port);
|
||||
view_port_free(view_port);
|
||||
furi_record_close(RECORD_GUI);
|
||||
furi_semaphore_free(semaphore);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
App(
|
||||
appid="notification_settings",
|
||||
name="LCD and Notifications",
|
||||
apptype=FlipperAppType.SETTINGS,
|
||||
entry_point="notification_settings_app",
|
||||
requires=["notification"],
|
||||
stack_size=1 * 1024,
|
||||
order=20,
|
||||
)
|
||||
@@ -0,0 +1,199 @@
|
||||
#include <furi.h>
|
||||
#include <notification/notification_app.h>
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <lib/toolbox/value_index.h>
|
||||
|
||||
#define MAX_NOTIFICATION_SETTINGS 4
|
||||
|
||||
typedef struct {
|
||||
NotificationApp* notification;
|
||||
Gui* gui;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
VariableItemList* variable_item_list;
|
||||
} NotificationAppSettings;
|
||||
|
||||
static const NotificationSequence sequence_note_c = {
|
||||
&message_note_c5,
|
||||
&message_delay_100,
|
||||
&message_sound_off,
|
||||
NULL,
|
||||
};
|
||||
|
||||
#define BACKLIGHT_COUNT 5
|
||||
const char* const backlight_text[BACKLIGHT_COUNT] = {
|
||||
"0%",
|
||||
"25%",
|
||||
"50%",
|
||||
"75%",
|
||||
"100%",
|
||||
};
|
||||
const float backlight_value[BACKLIGHT_COUNT] = {
|
||||
0.0f,
|
||||
0.25f,
|
||||
0.5f,
|
||||
0.75f,
|
||||
1.0f,
|
||||
};
|
||||
|
||||
#define VOLUME_COUNT 5
|
||||
const char* const volume_text[VOLUME_COUNT] = {
|
||||
"0%",
|
||||
"25%",
|
||||
"50%",
|
||||
"75%",
|
||||
"100%",
|
||||
};
|
||||
const float volume_value[VOLUME_COUNT] = {0.0f, 0.25f, 0.5f, 0.75f, 1.0f};
|
||||
|
||||
#define DELAY_COUNT 6
|
||||
const char* const delay_text[DELAY_COUNT] = {
|
||||
"1s",
|
||||
"5s",
|
||||
"15s",
|
||||
"30s",
|
||||
"60s",
|
||||
"120s",
|
||||
};
|
||||
const uint32_t delay_value[DELAY_COUNT] = {1000, 5000, 15000, 30000, 60000, 120000};
|
||||
|
||||
#define VIBRO_COUNT 2
|
||||
const char* const vibro_text[VIBRO_COUNT] = {
|
||||
"OFF",
|
||||
"ON",
|
||||
};
|
||||
const bool vibro_value[VIBRO_COUNT] = {false, true};
|
||||
|
||||
static void backlight_changed(VariableItem* item) {
|
||||
NotificationAppSettings* app = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
variable_item_set_current_value_text(item, backlight_text[index]);
|
||||
app->notification->settings.display_brightness = backlight_value[index];
|
||||
notification_message(app->notification, &sequence_display_backlight_on);
|
||||
}
|
||||
|
||||
static void screen_changed(VariableItem* item) {
|
||||
NotificationAppSettings* app = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
variable_item_set_current_value_text(item, delay_text[index]);
|
||||
app->notification->settings.display_off_delay_ms = delay_value[index];
|
||||
notification_message(app->notification, &sequence_display_backlight_on);
|
||||
}
|
||||
|
||||
const NotificationMessage apply_message = {
|
||||
.type = NotificationMessageTypeLedBrightnessSettingApply,
|
||||
};
|
||||
const NotificationSequence apply_sequence = {
|
||||
&apply_message,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void led_changed(VariableItem* item) {
|
||||
NotificationAppSettings* app = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
variable_item_set_current_value_text(item, backlight_text[index]);
|
||||
app->notification->settings.led_brightness = backlight_value[index];
|
||||
notification_message(app->notification, &apply_sequence);
|
||||
notification_internal_message(app->notification, &apply_sequence);
|
||||
notification_message(app->notification, &sequence_blink_white_100);
|
||||
}
|
||||
|
||||
static void volume_changed(VariableItem* item) {
|
||||
NotificationAppSettings* app = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
variable_item_set_current_value_text(item, volume_text[index]);
|
||||
app->notification->settings.speaker_volume = volume_value[index];
|
||||
notification_message(app->notification, &sequence_note_c);
|
||||
}
|
||||
|
||||
static void vibro_changed(VariableItem* item) {
|
||||
NotificationAppSettings* app = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
|
||||
variable_item_set_current_value_text(item, vibro_text[index]);
|
||||
app->notification->settings.vibro_on = vibro_value[index];
|
||||
notification_message(app->notification, &sequence_single_vibro);
|
||||
}
|
||||
|
||||
static uint32_t notification_app_settings_exit(void* context) {
|
||||
UNUSED(context);
|
||||
return VIEW_NONE;
|
||||
}
|
||||
|
||||
static NotificationAppSettings* alloc_settings() {
|
||||
NotificationAppSettings* app = malloc(sizeof(NotificationAppSettings));
|
||||
app->notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
|
||||
app->variable_item_list = variable_item_list_alloc();
|
||||
View* view = variable_item_list_get_view(app->variable_item_list);
|
||||
view_set_previous_callback(view, notification_app_settings_exit);
|
||||
|
||||
VariableItem* item;
|
||||
uint8_t value_index;
|
||||
|
||||
item = variable_item_list_add(
|
||||
app->variable_item_list, "LCD Backlight", BACKLIGHT_COUNT, backlight_changed, app);
|
||||
value_index = value_index_float(
|
||||
app->notification->settings.display_brightness, backlight_value, BACKLIGHT_COUNT);
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, backlight_text[value_index]);
|
||||
|
||||
item = variable_item_list_add(
|
||||
app->variable_item_list, "Backlight Time", DELAY_COUNT, screen_changed, app);
|
||||
value_index = value_index_uint32(
|
||||
app->notification->settings.display_off_delay_ms, delay_value, DELAY_COUNT);
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, delay_text[value_index]);
|
||||
|
||||
item = variable_item_list_add(
|
||||
app->variable_item_list, "LED Brightness", BACKLIGHT_COUNT, led_changed, app);
|
||||
value_index = value_index_float(
|
||||
app->notification->settings.led_brightness, backlight_value, BACKLIGHT_COUNT);
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, backlight_text[value_index]);
|
||||
|
||||
item = variable_item_list_add(
|
||||
app->variable_item_list, "Volume", VOLUME_COUNT, volume_changed, app);
|
||||
value_index =
|
||||
value_index_float(app->notification->settings.speaker_volume, volume_value, VOLUME_COUNT);
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, volume_text[value_index]);
|
||||
|
||||
item =
|
||||
variable_item_list_add(app->variable_item_list, "Vibro", VIBRO_COUNT, vibro_changed, app);
|
||||
value_index = value_index_bool(app->notification->settings.vibro_on, vibro_value, VIBRO_COUNT);
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, vibro_text[value_index]);
|
||||
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
view_dispatcher_add_view(app->view_dispatcher, 0, view);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, 0);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
static void free_settings(NotificationAppSettings* app) {
|
||||
view_dispatcher_remove_view(app->view_dispatcher, 0);
|
||||
variable_item_list_free(app->variable_item_list);
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
|
||||
furi_record_close(RECORD_GUI);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
free(app);
|
||||
}
|
||||
|
||||
int32_t notification_settings_app(void* p) {
|
||||
UNUSED(p);
|
||||
NotificationAppSettings* app = alloc_settings();
|
||||
view_dispatcher_run(app->view_dispatcher);
|
||||
notification_message_save_settings(app->notification);
|
||||
free_settings(app);
|
||||
return 0;
|
||||
}
|
||||
13
applications/settings/power_settings_app/application.fam
Normal file
13
applications/settings/power_settings_app/application.fam
Normal file
@@ -0,0 +1,13 @@
|
||||
App(
|
||||
appid="power_settings",
|
||||
name="Power",
|
||||
apptype=FlipperAppType.SETTINGS,
|
||||
entry_point="power_settings_app",
|
||||
requires=[
|
||||
"gui",
|
||||
"power",
|
||||
],
|
||||
flags=["InsomniaSafe"],
|
||||
stack_size=1 * 1024,
|
||||
order=40,
|
||||
)
|
||||
@@ -0,0 +1,86 @@
|
||||
#include "power_settings_app.h"
|
||||
|
||||
static bool power_settings_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
PowerSettingsApp* app = context;
|
||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||
}
|
||||
|
||||
static bool power_settings_back_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
PowerSettingsApp* app = context;
|
||||
return scene_manager_handle_back_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static void power_settings_tick_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
PowerSettingsApp* app = context;
|
||||
scene_manager_handle_tick_event(app->scene_manager);
|
||||
}
|
||||
|
||||
PowerSettingsApp* power_settings_app_alloc(uint32_t first_scene) {
|
||||
PowerSettingsApp* app = malloc(sizeof(PowerSettingsApp));
|
||||
|
||||
// Records
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
app->power = furi_record_open(RECORD_POWER);
|
||||
|
||||
// View dispatcher
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
app->scene_manager = scene_manager_alloc(&power_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, power_settings_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
app->view_dispatcher, power_settings_back_event_callback);
|
||||
view_dispatcher_set_tick_event_callback(
|
||||
app->view_dispatcher, power_settings_tick_event_callback, 2000);
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
// Views
|
||||
app->batery_info = battery_info_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
PowerSettingsAppViewBatteryInfo,
|
||||
battery_info_get_view(app->batery_info));
|
||||
app->submenu = submenu_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, PowerSettingsAppViewSubmenu, submenu_get_view(app->submenu));
|
||||
app->dialog = dialog_ex_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, PowerSettingsAppViewDialog, dialog_ex_get_view(app->dialog));
|
||||
|
||||
// Set first scene
|
||||
scene_manager_next_scene(app->scene_manager, first_scene);
|
||||
return app;
|
||||
}
|
||||
|
||||
void power_settings_app_free(PowerSettingsApp* app) {
|
||||
furi_assert(app);
|
||||
// Views
|
||||
view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewBatteryInfo);
|
||||
battery_info_free(app->batery_info);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewSubmenu);
|
||||
submenu_free(app->submenu);
|
||||
view_dispatcher_remove_view(app->view_dispatcher, PowerSettingsAppViewDialog);
|
||||
dialog_ex_free(app->dialog);
|
||||
// View dispatcher
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
scene_manager_free(app->scene_manager);
|
||||
// Records
|
||||
furi_record_close(RECORD_POWER);
|
||||
furi_record_close(RECORD_GUI);
|
||||
free(app);
|
||||
}
|
||||
|
||||
int32_t power_settings_app(void* p) {
|
||||
uint32_t first_scene = PowerSettingsAppSceneStart;
|
||||
if(p && strlen(p) && !strcmp(p, "off")) {
|
||||
first_scene = PowerSettingsAppScenePowerOff;
|
||||
}
|
||||
PowerSettingsApp* app = power_settings_app_alloc(first_scene);
|
||||
view_dispatcher_run(app->view_dispatcher);
|
||||
power_settings_app_free(app);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <power/power_service/power.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
#include "views/battery_info.h"
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/dialog_ex.h>
|
||||
|
||||
#include "scenes/power_settings_scene.h"
|
||||
|
||||
typedef struct {
|
||||
Power* power;
|
||||
Gui* gui;
|
||||
SceneManager* scene_manager;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
BatteryInfo* batery_info;
|
||||
Submenu* submenu;
|
||||
DialogEx* dialog;
|
||||
PowerInfo info;
|
||||
} PowerSettingsApp;
|
||||
|
||||
typedef enum {
|
||||
PowerSettingsAppViewBatteryInfo,
|
||||
PowerSettingsAppViewSubmenu,
|
||||
PowerSettingsAppViewDialog,
|
||||
} PowerSettingsAppView;
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "power_settings_scene.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const power_settings_on_enter_handlers[])(void*) = {
|
||||
#include "power_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 power_settings_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "power_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 power_settings_on_exit_handlers[])(void* context) = {
|
||||
#include "power_settings_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers power_settings_scene_handlers = {
|
||||
.on_enter_handlers = power_settings_on_enter_handlers,
|
||||
.on_event_handlers = power_settings_on_event_handlers,
|
||||
.on_exit_handlers = power_settings_on_exit_handlers,
|
||||
.scene_num = PowerSettingsAppSceneNum,
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) PowerSettingsAppScene##id,
|
||||
typedef enum {
|
||||
#include "power_settings_scene_config.h"
|
||||
PowerSettingsAppSceneNum,
|
||||
} PowerSettingsAppScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers power_settings_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "power_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 "power_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 "power_settings_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
@@ -0,0 +1,35 @@
|
||||
#include "../power_settings_app.h"
|
||||
|
||||
static void power_settings_scene_battery_info_update_model(PowerSettingsApp* app) {
|
||||
power_get_info(app->power, &app->info);
|
||||
BatteryInfoModel battery_info_data = {
|
||||
.vbus_voltage = app->info.voltage_vbus,
|
||||
.gauge_voltage = app->info.voltage_gauge,
|
||||
.gauge_current = app->info.current_gauge,
|
||||
.gauge_temperature = app->info.temperature_gauge,
|
||||
.charge = app->info.charge,
|
||||
.health = app->info.health,
|
||||
};
|
||||
battery_info_set_data(app->batery_info, &battery_info_data);
|
||||
}
|
||||
|
||||
void power_settings_scene_battery_info_on_enter(void* context) {
|
||||
PowerSettingsApp* app = context;
|
||||
power_settings_scene_battery_info_update_model(app);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, PowerSettingsAppViewBatteryInfo);
|
||||
}
|
||||
|
||||
bool power_settings_scene_battery_info_on_event(void* context, SceneManagerEvent event) {
|
||||
PowerSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeTick) {
|
||||
power_settings_scene_battery_info_update_model(app);
|
||||
consumed = true;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void power_settings_scene_battery_info_on_exit(void* context) {
|
||||
UNUSED(context);
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
ADD_SCENE(power_settings, start, Start)
|
||||
ADD_SCENE(power_settings, battery_info, BatteryInfo)
|
||||
ADD_SCENE(power_settings, reboot, Reboot)
|
||||
ADD_SCENE(power_settings, power_off, PowerOff)
|
||||
@@ -0,0 +1,46 @@
|
||||
#include "../power_settings_app.h"
|
||||
|
||||
void power_settings_scene_power_off_dialog_callback(DialogExResult result, void* context) {
|
||||
furi_assert(context);
|
||||
PowerSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void power_settings_scene_power_off_on_enter(void* context) {
|
||||
PowerSettingsApp* app = context;
|
||||
DialogEx* dialog = app->dialog;
|
||||
|
||||
dialog_ex_set_header(dialog, "Turn Off Device?", 64, 2, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(
|
||||
dialog, " I will be\nwaiting for\n you here...", 78, 16, AlignLeft, AlignTop);
|
||||
dialog_ex_set_icon(dialog, 21, 13, &I_Cry_dolph_55x52);
|
||||
dialog_ex_set_left_button_text(dialog, "Back");
|
||||
dialog_ex_set_right_button_text(dialog, "OFF");
|
||||
dialog_ex_set_result_callback(dialog, power_settings_scene_power_off_dialog_callback);
|
||||
dialog_ex_set_context(dialog, app);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, PowerSettingsAppViewDialog);
|
||||
}
|
||||
|
||||
bool power_settings_scene_power_off_on_event(void* context, SceneManagerEvent event) {
|
||||
PowerSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == DialogExResultLeft) {
|
||||
if(!scene_manager_previous_scene(app->scene_manager)) {
|
||||
scene_manager_stop(app->scene_manager);
|
||||
view_dispatcher_stop(app->view_dispatcher);
|
||||
}
|
||||
} else if(event.event == DialogExResultRight) {
|
||||
power_off(app->power);
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void power_settings_scene_power_off_on_exit(void* context) {
|
||||
PowerSettingsApp* app = context;
|
||||
dialog_ex_reset(app->dialog);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#include "../power_settings_app.h"
|
||||
|
||||
enum PowerSettingsRebootSubmenuIndex {
|
||||
PowerSettingsRebootSubmenuIndexDfu,
|
||||
PowerSettingsRebootSubmenuIndexOs,
|
||||
};
|
||||
|
||||
void power_settings_scene_reboot_submenu_callback(void* context, uint32_t index) {
|
||||
furi_assert(context);
|
||||
PowerSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void power_settings_scene_reboot_on_enter(void* context) {
|
||||
PowerSettingsApp* app = context;
|
||||
Submenu* submenu = app->submenu;
|
||||
|
||||
submenu_set_header(submenu, "Reboot type");
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Firmware upgrade",
|
||||
PowerSettingsRebootSubmenuIndexDfu,
|
||||
power_settings_scene_reboot_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Flipper OS",
|
||||
PowerSettingsRebootSubmenuIndexOs,
|
||||
power_settings_scene_reboot_submenu_callback,
|
||||
app);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, PowerSettingsAppViewSubmenu);
|
||||
}
|
||||
|
||||
bool power_settings_scene_reboot_on_event(void* context, SceneManagerEvent event) {
|
||||
UNUSED(context);
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == PowerSettingsRebootSubmenuIndexDfu) {
|
||||
power_reboot(PowerBootModeDfu);
|
||||
} else if(event.event == PowerSettingsRebootSubmenuIndexOs) {
|
||||
power_reboot(PowerBootModeNormal);
|
||||
}
|
||||
consumed = true;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void power_settings_scene_reboot_on_exit(void* context) {
|
||||
PowerSettingsApp* app = context;
|
||||
submenu_reset(app->submenu);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
#include "../power_settings_app.h"
|
||||
|
||||
enum PowerSettingsSubmenuIndex {
|
||||
PowerSettingsSubmenuIndexBatteryInfo,
|
||||
PowerSettingsSubmenuIndexReboot,
|
||||
PowerSettingsSubmenuIndexOff,
|
||||
};
|
||||
|
||||
static void power_settings_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||
furi_assert(context);
|
||||
PowerSettingsApp* app = context;
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void power_settings_scene_start_on_enter(void* context) {
|
||||
PowerSettingsApp* app = context;
|
||||
Submenu* submenu = app->submenu;
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Battery Info",
|
||||
PowerSettingsSubmenuIndexBatteryInfo,
|
||||
power_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Reboot",
|
||||
PowerSettingsSubmenuIndexReboot,
|
||||
power_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Power OFF",
|
||||
PowerSettingsSubmenuIndexOff,
|
||||
power_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(app->scene_manager, PowerSettingsAppSceneStart));
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, PowerSettingsAppViewSubmenu);
|
||||
}
|
||||
|
||||
bool power_settings_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
PowerSettingsApp* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
if(event.event == PowerSettingsSubmenuIndexBatteryInfo) {
|
||||
scene_manager_next_scene(app->scene_manager, PowerSettingsAppSceneBatteryInfo);
|
||||
} else if(event.event == PowerSettingsSubmenuIndexReboot) {
|
||||
scene_manager_next_scene(app->scene_manager, PowerSettingsAppSceneReboot);
|
||||
} else if(event.event == PowerSettingsSubmenuIndexOff) {
|
||||
scene_manager_next_scene(app->scene_manager, PowerSettingsAppScenePowerOff);
|
||||
}
|
||||
scene_manager_set_scene_state(app->scene_manager, PowerSettingsAppSceneStart, event.event);
|
||||
consumed = true;
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void power_settings_scene_start_on_exit(void* context) {
|
||||
PowerSettingsApp* app = context;
|
||||
submenu_reset(app->submenu);
|
||||
}
|
||||
126
applications/settings/power_settings_app/views/battery_info.c
Normal file
126
applications/settings/power_settings_app/views/battery_info.c
Normal file
@@ -0,0 +1,126 @@
|
||||
#include "battery_info.h"
|
||||
#include <furi.h>
|
||||
#include <gui/elements.h>
|
||||
|
||||
struct BatteryInfo {
|
||||
View* view;
|
||||
};
|
||||
|
||||
static void draw_stat(Canvas* canvas, int x, int y, const Icon* icon, char* val) {
|
||||
canvas_draw_frame(canvas, x - 7, y + 7, 30, 13);
|
||||
canvas_draw_icon(canvas, x, y, icon);
|
||||
canvas_set_color(canvas, ColorWhite);
|
||||
canvas_draw_box(canvas, x - 4, y + 16, 24, 6);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
canvas_draw_str_aligned(canvas, x + 8, y + 22, AlignCenter, AlignBottom, val);
|
||||
};
|
||||
|
||||
static void draw_battery(Canvas* canvas, BatteryInfoModel* data, int x, int y) {
|
||||
char emote[20] = {};
|
||||
char header[20] = {};
|
||||
char value[20] = {};
|
||||
|
||||
int32_t drain_current = data->gauge_current * (-1000);
|
||||
uint32_t charge_current = data->gauge_current * 1000;
|
||||
|
||||
// Draw battery
|
||||
canvas_draw_icon(canvas, x, y, &I_BatteryBody_52x28);
|
||||
if(charge_current > 0) {
|
||||
canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceCharging_29x14);
|
||||
} else if(drain_current > 100) {
|
||||
canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceConfused_29x14);
|
||||
} else if(data->charge < 10) {
|
||||
canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceNopower_29x14);
|
||||
} else {
|
||||
canvas_draw_icon(canvas, x + 16, y + 7, &I_FaceNormal_29x14);
|
||||
}
|
||||
|
||||
// Draw bubble
|
||||
elements_bubble(canvas, 53, 0, 71, 39);
|
||||
|
||||
// Set text
|
||||
if(charge_current > 0) {
|
||||
snprintf(emote, sizeof(emote), "%s", "Yummy!");
|
||||
snprintf(header, sizeof(header), "%s", "Charging at");
|
||||
snprintf(
|
||||
value,
|
||||
sizeof(value),
|
||||
"%ld.%ldV %ldmA",
|
||||
(uint32_t)(data->vbus_voltage),
|
||||
(uint32_t)(data->vbus_voltage * 10) % 10,
|
||||
charge_current);
|
||||
} else if(drain_current > 0) {
|
||||
snprintf(emote, sizeof(emote), "%s", drain_current > 100 ? "Oh no!" : "Om-nom-nom!");
|
||||
snprintf(header, sizeof(header), "%s", "Consumption is");
|
||||
snprintf(
|
||||
value, sizeof(value), "%ld %s", drain_current, drain_current > 100 ? "mA!" : "mA");
|
||||
} else if(charge_current != 0 || drain_current != 0) {
|
||||
snprintf(header, 20, "...");
|
||||
} else {
|
||||
snprintf(header, sizeof(header), "Charged!");
|
||||
}
|
||||
|
||||
canvas_draw_str_aligned(canvas, 92, y + 3, AlignCenter, AlignCenter, emote);
|
||||
canvas_draw_str_aligned(canvas, 92, y + 15, AlignCenter, AlignCenter, header);
|
||||
canvas_draw_str_aligned(canvas, 92, y + 27, AlignCenter, AlignCenter, value);
|
||||
};
|
||||
|
||||
static void battery_info_draw_callback(Canvas* canvas, void* context) {
|
||||
furi_assert(context);
|
||||
BatteryInfoModel* model = context;
|
||||
|
||||
canvas_clear(canvas);
|
||||
canvas_set_color(canvas, ColorBlack);
|
||||
draw_battery(canvas, model, 0, 5);
|
||||
|
||||
char batt_level[10];
|
||||
char temperature[10];
|
||||
char voltage[10];
|
||||
char health[10];
|
||||
|
||||
snprintf(batt_level, sizeof(batt_level), "%ld%%", (uint32_t)model->charge);
|
||||
snprintf(temperature, sizeof(temperature), "%ld C", (uint32_t)model->gauge_temperature);
|
||||
snprintf(
|
||||
voltage,
|
||||
sizeof(voltage),
|
||||
"%ld.%01ld V",
|
||||
(uint32_t)model->gauge_voltage,
|
||||
(uint32_t)(model->gauge_voltage * 10) % 10);
|
||||
snprintf(health, sizeof(health), "%d%%", model->health);
|
||||
|
||||
draw_stat(canvas, 8, 42, &I_Battery_16x16, batt_level);
|
||||
draw_stat(canvas, 40, 42, &I_Temperature_16x16, temperature);
|
||||
draw_stat(canvas, 72, 42, &I_Voltage_16x16, voltage);
|
||||
draw_stat(canvas, 104, 42, &I_Health_16x16, health);
|
||||
}
|
||||
|
||||
BatteryInfo* battery_info_alloc() {
|
||||
BatteryInfo* battery_info = malloc(sizeof(BatteryInfo));
|
||||
battery_info->view = view_alloc();
|
||||
view_set_context(battery_info->view, battery_info);
|
||||
view_allocate_model(battery_info->view, ViewModelTypeLocking, sizeof(BatteryInfoModel));
|
||||
view_set_draw_callback(battery_info->view, battery_info_draw_callback);
|
||||
|
||||
return battery_info;
|
||||
}
|
||||
|
||||
void battery_info_free(BatteryInfo* battery_info) {
|
||||
furi_assert(battery_info);
|
||||
view_free(battery_info->view);
|
||||
free(battery_info);
|
||||
}
|
||||
|
||||
View* battery_info_get_view(BatteryInfo* battery_info) {
|
||||
furi_assert(battery_info);
|
||||
return battery_info->view;
|
||||
}
|
||||
|
||||
void battery_info_set_data(BatteryInfo* battery_info, BatteryInfoModel* data) {
|
||||
furi_assert(battery_info);
|
||||
furi_assert(data);
|
||||
with_view_model(
|
||||
battery_info->view, (BatteryInfoModel * model) {
|
||||
memcpy(model, data, sizeof(BatteryInfoModel));
|
||||
return true;
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/view.h>
|
||||
|
||||
typedef struct BatteryInfo BatteryInfo;
|
||||
|
||||
typedef struct {
|
||||
float vbus_voltage;
|
||||
float gauge_voltage;
|
||||
float gauge_current;
|
||||
float gauge_temperature;
|
||||
uint8_t charge;
|
||||
uint8_t health;
|
||||
} BatteryInfoModel;
|
||||
|
||||
BatteryInfo* battery_info_alloc();
|
||||
|
||||
void battery_info_free(BatteryInfo* battery_info);
|
||||
|
||||
View* battery_info_get_view(BatteryInfo* battery_info);
|
||||
|
||||
void battery_info_set_data(BatteryInfo* battery_info, BatteryInfoModel* data);
|
||||
9
applications/settings/storage_settings/application.fam
Normal file
9
applications/settings/storage_settings/application.fam
Normal file
@@ -0,0 +1,9 @@
|
||||
App(
|
||||
appid="storage_settings",
|
||||
name="Storage",
|
||||
apptype=FlipperAppType.SETTINGS,
|
||||
entry_point="storage_settings_app",
|
||||
requires=["storage"],
|
||||
stack_size=2 * 1024,
|
||||
order=30,
|
||||
)
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "storage_settings_scene.h"
|
||||
|
||||
// Generate scene on_enter handlers array
|
||||
#define ADD_SCENE(prefix, name, id) prefix##_scene_##name##_on_enter,
|
||||
void (*const storage_settings_on_enter_handlers[])(void*) = {
|
||||
#include "storage_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 storage_settings_on_event_handlers[])(void* context, SceneManagerEvent event) = {
|
||||
#include "storage_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 storage_settings_on_exit_handlers[])(void* context) = {
|
||||
#include "storage_settings_scene_config.h"
|
||||
};
|
||||
#undef ADD_SCENE
|
||||
|
||||
// Initialize scene handlers configuration structure
|
||||
const SceneManagerHandlers storage_settings_scene_handlers = {
|
||||
.on_enter_handlers = storage_settings_on_enter_handlers,
|
||||
.on_event_handlers = storage_settings_on_event_handlers,
|
||||
.on_exit_handlers = storage_settings_on_exit_handlers,
|
||||
.scene_num = StorageSettingsSceneNum,
|
||||
};
|
||||
@@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
#include <gui/scene_manager.h>
|
||||
|
||||
// Generate scene id and total number
|
||||
#define ADD_SCENE(prefix, name, id) StorageSettings##id,
|
||||
typedef enum {
|
||||
#include "storage_settings_scene_config.h"
|
||||
StorageSettingsSceneNum,
|
||||
} StorageSettingsScene;
|
||||
#undef ADD_SCENE
|
||||
|
||||
extern const SceneManagerHandlers storage_settings_scene_handlers;
|
||||
|
||||
// Generate scene on_enter handlers declaration
|
||||
#define ADD_SCENE(prefix, name, id) void prefix##_scene_##name##_on_enter(void*);
|
||||
#include "storage_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 "storage_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 "storage_settings_scene_config.h"
|
||||
#undef ADD_SCENE
|
||||
@@ -0,0 +1,163 @@
|
||||
#include "../storage_settings.h"
|
||||
#include <furi_hal.h>
|
||||
|
||||
#define BENCH_DATA_SIZE 4096
|
||||
#define BENCH_COUNT 6
|
||||
#define BENCH_REPEATS 4
|
||||
#define BENCH_FILE EXT_PATH("rwfiletest.bin")
|
||||
|
||||
static void
|
||||
storage_settings_scene_benchmark_dialog_callback(DialogExResult result, void* context) {
|
||||
StorageSettings* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
|
||||
static bool storage_settings_scene_bench_write(
|
||||
Storage* api,
|
||||
uint16_t size,
|
||||
const uint8_t* data,
|
||||
uint32_t* speed) {
|
||||
File* file = storage_file_alloc(api);
|
||||
bool result = true;
|
||||
if(storage_file_open(file, BENCH_FILE, FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
|
||||
uint32_t ticks;
|
||||
ticks = furi_get_tick();
|
||||
|
||||
for(size_t repeat = 0; repeat < BENCH_REPEATS; repeat++) {
|
||||
for(size_t i = 0; i < BENCH_DATA_SIZE / size; i++) {
|
||||
if(storage_file_write(file, (data + i * size), size) != size) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ticks = furi_get_tick() - ticks;
|
||||
*speed = BENCH_DATA_SIZE * furi_kernel_get_tick_frequency() * BENCH_REPEATS;
|
||||
*speed /= ticks;
|
||||
*speed /= 1024;
|
||||
}
|
||||
storage_file_close(file);
|
||||
storage_file_free(file);
|
||||
return result;
|
||||
}
|
||||
|
||||
static bool
|
||||
storage_settings_scene_bench_read(Storage* api, uint16_t size, uint8_t* data, uint32_t* speed) {
|
||||
File* file = storage_file_alloc(api);
|
||||
bool result = true;
|
||||
*speed = -1;
|
||||
|
||||
if(storage_file_open(file, BENCH_FILE, FSAM_READ, FSOM_OPEN_EXISTING)) {
|
||||
uint32_t ticks;
|
||||
ticks = furi_get_tick();
|
||||
|
||||
for(size_t repeat = 0; repeat < BENCH_REPEATS; repeat++) {
|
||||
for(size_t i = 0; i < BENCH_DATA_SIZE / size; i++) {
|
||||
if(storage_file_read(file, (data + i * size), size) != size) {
|
||||
result = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ticks = furi_get_tick() - ticks;
|
||||
*speed = BENCH_DATA_SIZE * furi_kernel_get_tick_frequency() * BENCH_REPEATS;
|
||||
*speed /= ticks;
|
||||
*speed /= 1024;
|
||||
}
|
||||
storage_file_close(file);
|
||||
storage_file_free(file);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void storage_settings_scene_benchmark(StorageSettings* app) {
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
uint8_t* bench_data;
|
||||
dialog_ex_set_header(dialog_ex, "Preparing Data...", 64, 32, AlignCenter, AlignCenter);
|
||||
|
||||
bench_data = malloc(BENCH_DATA_SIZE);
|
||||
for(size_t i = 0; i < BENCH_DATA_SIZE; i++) {
|
||||
bench_data[i] = (uint8_t)i;
|
||||
}
|
||||
|
||||
uint16_t bench_size[BENCH_COUNT] = {1, 8, 32, 256, 512, 1024};
|
||||
uint32_t bench_w_speed[BENCH_COUNT] = {0, 0, 0, 0, 0, 0};
|
||||
uint32_t bench_r_speed[BENCH_COUNT] = {0, 0, 0, 0, 0, 0};
|
||||
|
||||
dialog_ex_set_header(dialog_ex, "Benchmarking...", 64, 32, AlignCenter, AlignCenter);
|
||||
for(size_t i = 0; i < BENCH_COUNT; i++) {
|
||||
if(!storage_settings_scene_bench_write(
|
||||
app->fs_api, bench_size[i], bench_data, &bench_w_speed[i]))
|
||||
break;
|
||||
|
||||
if(i > 0) string_cat_printf(app->text_string, "\n");
|
||||
string_cat_printf(app->text_string, "%ub : W %luK ", bench_size[i], bench_w_speed[i]);
|
||||
dialog_ex_set_header(dialog_ex, NULL, 0, 0, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, string_get_cstr(app->text_string), 0, 32, AlignLeft, AlignCenter);
|
||||
|
||||
if(!storage_settings_scene_bench_read(
|
||||
app->fs_api, bench_size[i], bench_data, &bench_r_speed[i]))
|
||||
break;
|
||||
|
||||
string_cat_printf(app->text_string, "R %luK", bench_r_speed[i]);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, string_get_cstr(app->text_string), 0, 32, AlignLeft, AlignCenter);
|
||||
}
|
||||
|
||||
free(bench_data);
|
||||
}
|
||||
|
||||
void storage_settings_scene_benchmark_on_enter(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
FS_Error sd_status = storage_sd_status(app->fs_api);
|
||||
scene_manager_set_scene_state(app->scene_manager, StorageSettingsBenchmark, sd_status);
|
||||
|
||||
dialog_ex_set_context(dialog_ex, app);
|
||||
dialog_ex_set_result_callback(dialog_ex, storage_settings_scene_benchmark_dialog_callback);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx);
|
||||
|
||||
if(sd_status != FSE_OK) {
|
||||
dialog_ex_set_icon(dialog_ex, 72, 17, &I_DolphinCommon_56x48);
|
||||
dialog_ex_set_header(dialog_ex, "SD Card Not Mounted", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop);
|
||||
dialog_ex_set_center_button_text(dialog_ex, "Ok");
|
||||
} else {
|
||||
storage_settings_scene_benchmark(app);
|
||||
notification_message(app->notification, &sequence_blink_green_100);
|
||||
}
|
||||
}
|
||||
|
||||
bool storage_settings_scene_benchmark_on_event(void* context, SceneManagerEvent event) {
|
||||
StorageSettings* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
FS_Error sd_status =
|
||||
scene_manager_get_scene_state(app->scene_manager, StorageSettingsBenchmark);
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DialogExResultCenter:
|
||||
consumed = scene_manager_previous_scene(app->scene_manager);
|
||||
break;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack && sd_status != FSE_OK) {
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void storage_settings_scene_benchmark_on_exit(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_reset(dialog_ex);
|
||||
|
||||
string_reset(app->text_string);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
ADD_SCENE(storage_settings, start, Start)
|
||||
ADD_SCENE(storage_settings, unmount_confirm, UnmountConfirm)
|
||||
ADD_SCENE(storage_settings, unmounted, Unmounted)
|
||||
ADD_SCENE(storage_settings, format_confirm, FormatConfirm)
|
||||
ADD_SCENE(storage_settings, formatting, Formatting)
|
||||
ADD_SCENE(storage_settings, sd_info, SDInfo)
|
||||
ADD_SCENE(storage_settings, internal_info, InternalInfo)
|
||||
ADD_SCENE(storage_settings, benchmark, Benchmark)
|
||||
ADD_SCENE(storage_settings, factory_reset, FactoryReset)
|
||||
@@ -0,0 +1,87 @@
|
||||
#include "../storage_settings.h"
|
||||
#include <power/power_service/power.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#define STORAGE_SETTINGS_SCENE_FACTORY_RESET_CONFIRM_COUNT 5
|
||||
|
||||
static void
|
||||
storage_settings_scene_factory_reset_dialog_callback(DialogExResult result, void* context) {
|
||||
StorageSettings* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void storage_settings_scene_factory_reset_on_enter(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_set_context(dialog_ex, app);
|
||||
dialog_ex_set_result_callback(dialog_ex, storage_settings_scene_factory_reset_dialog_callback);
|
||||
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Cancel");
|
||||
dialog_ex_set_right_button_text(dialog_ex, "Erase");
|
||||
|
||||
dialog_ex_set_header(dialog_ex, "Confirm Factory Reset", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex,
|
||||
"Internal storage will be erased\r\nData and setting will be lost!",
|
||||
64,
|
||||
32,
|
||||
AlignCenter,
|
||||
AlignCenter);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx);
|
||||
}
|
||||
|
||||
bool storage_settings_scene_factory_reset_on_event(void* context, SceneManagerEvent event) {
|
||||
StorageSettings* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
uint32_t counter =
|
||||
scene_manager_get_scene_state(app->scene_manager, StorageSettingsFactoryReset);
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DialogExResultLeft:
|
||||
scene_manager_set_scene_state(app->scene_manager, StorageSettingsFactoryReset, 0);
|
||||
consumed = scene_manager_previous_scene(app->scene_manager);
|
||||
break;
|
||||
case DialogExResultRight:
|
||||
counter++;
|
||||
if(counter < STORAGE_SETTINGS_SCENE_FACTORY_RESET_CONFIRM_COUNT) {
|
||||
string_printf(
|
||||
app->text_string,
|
||||
"%ld presses left",
|
||||
STORAGE_SETTINGS_SCENE_FACTORY_RESET_CONFIRM_COUNT - counter);
|
||||
dialog_ex_set_text(
|
||||
app->dialog_ex,
|
||||
string_get_cstr(app->text_string),
|
||||
64,
|
||||
32,
|
||||
AlignCenter,
|
||||
AlignCenter);
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, StorageSettingsFactoryReset, counter);
|
||||
} else {
|
||||
furi_hal_rtc_set_flag(FuriHalRtcFlagFactoryReset);
|
||||
power_reboot(PowerBootModeNormal);
|
||||
}
|
||||
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void storage_settings_scene_factory_reset_on_exit(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_reset(dialog_ex);
|
||||
|
||||
string_reset(app->text_string);
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
#include "../storage_settings.h"
|
||||
|
||||
static void
|
||||
storage_settings_scene_format_confirm_dialog_callback(DialogExResult result, void* context) {
|
||||
StorageSettings* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void storage_settings_scene_format_confirm_on_enter(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
FS_Error sd_status = storage_sd_status(app->fs_api);
|
||||
|
||||
if(sd_status == FSE_NOT_READY) {
|
||||
dialog_ex_set_icon(dialog_ex, 72, 17, &I_DolphinCommon_56x48);
|
||||
dialog_ex_set_header(dialog_ex, "SD Card Not Mounted", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop);
|
||||
dialog_ex_set_center_button_text(dialog_ex, "Ok");
|
||||
} else {
|
||||
dialog_ex_set_header(dialog_ex, "Format SD Card?", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(dialog_ex, "All data will be lost!", 64, 32, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Cancel");
|
||||
dialog_ex_set_right_button_text(dialog_ex, "Format");
|
||||
}
|
||||
|
||||
dialog_ex_set_context(dialog_ex, app);
|
||||
dialog_ex_set_result_callback(
|
||||
dialog_ex, storage_settings_scene_format_confirm_dialog_callback);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx);
|
||||
}
|
||||
|
||||
bool storage_settings_scene_format_confirm_on_event(void* context, SceneManagerEvent event) {
|
||||
StorageSettings* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DialogExResultLeft:
|
||||
consumed = scene_manager_previous_scene(app->scene_manager);
|
||||
break;
|
||||
case DialogExResultCenter:
|
||||
consumed = scene_manager_previous_scene(app->scene_manager);
|
||||
break;
|
||||
case DialogExResultRight:
|
||||
scene_manager_next_scene(app->scene_manager, StorageSettingsFormatting);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void storage_settings_scene_format_confirm_on_exit(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_reset(dialog_ex);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
#include "../storage_settings.h"
|
||||
|
||||
static const NotificationMessage message_green_165 = {
|
||||
.type = NotificationMessageTypeLedGreen,
|
||||
.data.led.value = 165,
|
||||
};
|
||||
|
||||
static const NotificationSequence sequence_set_formatting_leds = {
|
||||
&message_red_255,
|
||||
&message_green_165,
|
||||
&message_blue_0,
|
||||
&message_do_not_reset,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static const NotificationSequence sequence_reset_formatting_leds = {
|
||||
&message_red_0,
|
||||
&message_green_0,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void
|
||||
storage_settings_scene_formatting_dialog_callback(DialogExResult result, void* context) {
|
||||
StorageSettings* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void storage_settings_scene_formatting_on_enter(void* context) {
|
||||
StorageSettings* app = context;
|
||||
FS_Error error;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_set_header(dialog_ex, "Formatting...", 64, 32, AlignCenter, AlignCenter);
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx);
|
||||
|
||||
notification_message_block(app->notification, &sequence_set_formatting_leds);
|
||||
error = storage_sd_format(app->fs_api);
|
||||
notification_message(app->notification, &sequence_reset_formatting_leds);
|
||||
notification_message(app->notification, &sequence_blink_green_100);
|
||||
|
||||
dialog_ex_set_context(dialog_ex, app);
|
||||
dialog_ex_set_result_callback(dialog_ex, storage_settings_scene_formatting_dialog_callback);
|
||||
|
||||
if(error != FSE_OK) {
|
||||
dialog_ex_set_header(dialog_ex, "Cannot Format SD Card", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, storage_error_get_desc(error), 64, 32, AlignCenter, AlignCenter);
|
||||
} else {
|
||||
dialog_ex_set_icon(dialog_ex, 72, 17, &I_DolphinCommon_56x48);
|
||||
dialog_ex_set_header(dialog_ex, "Format\ncomplete!", 14, 15, AlignLeft, AlignTop);
|
||||
}
|
||||
dialog_ex_set_center_button_text(dialog_ex, "OK");
|
||||
}
|
||||
|
||||
bool storage_settings_scene_formatting_on_event(void* context, SceneManagerEvent event) {
|
||||
StorageSettings* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DialogExResultCenter:
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, StorageSettingsStart);
|
||||
break;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void storage_settings_scene_formatting_on_exit(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_reset(dialog_ex);
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "../storage_settings.h"
|
||||
#include <furi_hal_version.h>
|
||||
|
||||
static void
|
||||
storage_settings_scene_internal_info_dialog_callback(DialogExResult result, void* context) {
|
||||
StorageSettings* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void storage_settings_scene_internal_info_on_enter(void* context) {
|
||||
StorageSettings* app = context;
|
||||
uint64_t total_space;
|
||||
uint64_t free_space;
|
||||
FS_Error error =
|
||||
storage_common_fs_info(app->fs_api, STORAGE_INT_PATH_PREFIX, &total_space, &free_space);
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_set_context(dialog_ex, app);
|
||||
dialog_ex_set_result_callback(dialog_ex, storage_settings_scene_internal_info_dialog_callback);
|
||||
|
||||
if(error != FSE_OK) {
|
||||
dialog_ex_set_header(
|
||||
dialog_ex, "Internal Storage Error", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, storage_error_get_desc(error), 64, 32, AlignCenter, AlignCenter);
|
||||
} else {
|
||||
string_printf(
|
||||
app->text_string,
|
||||
"Label: %s\nType: LittleFS\n%lu KB total\n%lu KB free",
|
||||
furi_hal_version_get_name_ptr() ? furi_hal_version_get_name_ptr() : "Unknown",
|
||||
(uint32_t)(total_space / 1024),
|
||||
(uint32_t)(free_space / 1024));
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, string_get_cstr(app->text_string), 4, 4, AlignLeft, AlignTop);
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx);
|
||||
}
|
||||
|
||||
bool storage_settings_scene_internal_info_on_event(void* context, SceneManagerEvent event) {
|
||||
StorageSettings* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DialogExResultLeft:
|
||||
consumed = scene_manager_previous_scene(app->scene_manager);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void storage_settings_scene_internal_info_on_exit(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_reset(dialog_ex);
|
||||
|
||||
string_reset(app->text_string);
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
#include "../storage_settings.h"
|
||||
|
||||
static void storage_settings_scene_sd_info_dialog_callback(DialogExResult result, void* context) {
|
||||
StorageSettings* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void storage_settings_scene_sd_info_on_enter(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
SDInfo sd_info;
|
||||
FS_Error sd_status = storage_sd_info(app->fs_api, &sd_info);
|
||||
scene_manager_set_scene_state(app->scene_manager, StorageSettingsSDInfo, sd_status);
|
||||
|
||||
dialog_ex_set_context(dialog_ex, app);
|
||||
dialog_ex_set_result_callback(dialog_ex, storage_settings_scene_sd_info_dialog_callback);
|
||||
|
||||
if(sd_status != FSE_OK) {
|
||||
dialog_ex_set_icon(dialog_ex, 72, 17, &I_DolphinCommon_56x48);
|
||||
dialog_ex_set_header(dialog_ex, "SD Card Not Mounted", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop);
|
||||
dialog_ex_set_center_button_text(dialog_ex, "Ok");
|
||||
} else {
|
||||
string_printf(
|
||||
app->text_string,
|
||||
"Label: %s\nType: %s\n%lu KB total\n%lu KB free",
|
||||
sd_info.label,
|
||||
sd_api_get_fs_type_text(sd_info.fs_type),
|
||||
sd_info.kb_total,
|
||||
sd_info.kb_free);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, string_get_cstr(app->text_string), 4, 4, AlignLeft, AlignTop);
|
||||
}
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx);
|
||||
}
|
||||
|
||||
bool storage_settings_scene_sd_info_on_event(void* context, SceneManagerEvent event) {
|
||||
StorageSettings* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
FS_Error sd_status = scene_manager_get_scene_state(app->scene_manager, StorageSettingsSDInfo);
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DialogExResultLeft:
|
||||
consumed = scene_manager_previous_scene(app->scene_manager);
|
||||
break;
|
||||
case DialogExResultCenter:
|
||||
consumed = scene_manager_previous_scene(app->scene_manager);
|
||||
break;
|
||||
case DialogExResultRight:
|
||||
scene_manager_next_scene(app->scene_manager, StorageSettingsUnmounted);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack && sd_status != FSE_OK) {
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void storage_settings_scene_sd_info_on_exit(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_reset(dialog_ex);
|
||||
|
||||
string_reset(app->text_string);
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
#include "../storage_settings.h"
|
||||
|
||||
enum StorageSettingsStartSubmenuIndex {
|
||||
StorageSettingsStartSubmenuIndexInternalInfo,
|
||||
StorageSettingsStartSubmenuIndexSDInfo,
|
||||
StorageSettingsStartSubmenuIndexUnmount,
|
||||
StorageSettingsStartSubmenuIndexFormat,
|
||||
StorageSettingsStartSubmenuIndexBenchy,
|
||||
StorageSettingsStartSubmenuIndexFactoryReset
|
||||
};
|
||||
|
||||
static void storage_settings_scene_start_submenu_callback(void* context, uint32_t index) {
|
||||
StorageSettings* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, index);
|
||||
}
|
||||
|
||||
void storage_settings_scene_start_on_enter(void* context) {
|
||||
StorageSettings* app = context;
|
||||
Submenu* submenu = app->submenu;
|
||||
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"About Internal Storage",
|
||||
StorageSettingsStartSubmenuIndexInternalInfo,
|
||||
storage_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"About SD Card",
|
||||
StorageSettingsStartSubmenuIndexSDInfo,
|
||||
storage_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Unmount SD Card",
|
||||
StorageSettingsStartSubmenuIndexUnmount,
|
||||
storage_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Format SD Card",
|
||||
StorageSettingsStartSubmenuIndexFormat,
|
||||
storage_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Benchmark SD Card",
|
||||
StorageSettingsStartSubmenuIndexBenchy,
|
||||
storage_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
submenu_add_item(
|
||||
submenu,
|
||||
"Factory Reset",
|
||||
StorageSettingsStartSubmenuIndexFactoryReset,
|
||||
storage_settings_scene_start_submenu_callback,
|
||||
app);
|
||||
|
||||
submenu_set_selected_item(
|
||||
submenu, scene_manager_get_scene_state(app->scene_manager, StorageSettingsStart));
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewSubmenu);
|
||||
}
|
||||
|
||||
bool storage_settings_scene_start_on_event(void* context, SceneManagerEvent event) {
|
||||
StorageSettings* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case StorageSettingsStartSubmenuIndexSDInfo:
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, StorageSettingsStart, StorageSettingsStartSubmenuIndexSDInfo);
|
||||
scene_manager_next_scene(app->scene_manager, StorageSettingsSDInfo);
|
||||
consumed = true;
|
||||
break;
|
||||
case StorageSettingsStartSubmenuIndexInternalInfo:
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager,
|
||||
StorageSettingsStart,
|
||||
StorageSettingsStartSubmenuIndexInternalInfo);
|
||||
scene_manager_next_scene(app->scene_manager, StorageSettingsInternalInfo);
|
||||
consumed = true;
|
||||
break;
|
||||
case StorageSettingsStartSubmenuIndexUnmount:
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, StorageSettingsStart, StorageSettingsStartSubmenuIndexUnmount);
|
||||
scene_manager_next_scene(app->scene_manager, StorageSettingsUnmountConfirm);
|
||||
consumed = true;
|
||||
break;
|
||||
case StorageSettingsStartSubmenuIndexFormat:
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, StorageSettingsStart, StorageSettingsStartSubmenuIndexFormat);
|
||||
scene_manager_next_scene(app->scene_manager, StorageSettingsFormatConfirm);
|
||||
consumed = true;
|
||||
break;
|
||||
case StorageSettingsStartSubmenuIndexBenchy:
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager, StorageSettingsStart, StorageSettingsStartSubmenuIndexBenchy);
|
||||
scene_manager_next_scene(app->scene_manager, StorageSettingsBenchmark);
|
||||
consumed = true;
|
||||
break;
|
||||
case StorageSettingsStartSubmenuIndexFactoryReset:
|
||||
scene_manager_set_scene_state(
|
||||
app->scene_manager,
|
||||
StorageSettingsStart,
|
||||
StorageSettingsStartSubmenuIndexFactoryReset);
|
||||
scene_manager_next_scene(app->scene_manager, StorageSettingsFactoryReset);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void storage_settings_scene_start_on_exit(void* context) {
|
||||
StorageSettings* app = context;
|
||||
submenu_reset(app->submenu);
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
#include "../storage_settings.h"
|
||||
|
||||
static void
|
||||
storage_settings_scene_unmount_confirm_dialog_callback(DialogExResult result, void* context) {
|
||||
StorageSettings* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void storage_settings_scene_unmount_confirm_on_enter(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
FS_Error sd_status = storage_sd_status(app->fs_api);
|
||||
|
||||
if(sd_status == FSE_NOT_READY) {
|
||||
dialog_ex_set_icon(dialog_ex, 72, 17, &I_DolphinCommon_56x48);
|
||||
dialog_ex_set_header(dialog_ex, "SD Card Not Mounted", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, "Try to reinsert\nor format SD\ncard.", 3, 19, AlignLeft, AlignTop);
|
||||
dialog_ex_set_center_button_text(dialog_ex, "Ok");
|
||||
} else {
|
||||
dialog_ex_set_header(dialog_ex, "Unmount SD Card?", 64, 10, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_text(
|
||||
dialog_ex, "SD card will be\nunavailable", 64, 32, AlignCenter, AlignCenter);
|
||||
dialog_ex_set_left_button_text(dialog_ex, "Cancel");
|
||||
dialog_ex_set_right_button_text(dialog_ex, "Unmount");
|
||||
}
|
||||
|
||||
dialog_ex_set_context(dialog_ex, app);
|
||||
dialog_ex_set_result_callback(
|
||||
dialog_ex, storage_settings_scene_unmount_confirm_dialog_callback);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx);
|
||||
}
|
||||
|
||||
bool storage_settings_scene_unmount_confirm_on_event(void* context, SceneManagerEvent event) {
|
||||
StorageSettings* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DialogExResultCenter:
|
||||
consumed = scene_manager_previous_scene(app->scene_manager);
|
||||
break;
|
||||
case DialogExResultLeft:
|
||||
consumed = scene_manager_previous_scene(app->scene_manager);
|
||||
break;
|
||||
case DialogExResultRight:
|
||||
scene_manager_next_scene(app->scene_manager, StorageSettingsUnmounted);
|
||||
consumed = true;
|
||||
break;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void storage_settings_scene_unmount_confirm_on_exit(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_reset(dialog_ex);
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
#include "../storage_settings.h"
|
||||
|
||||
static void
|
||||
storage_settings_scene_unmounted_dialog_callback(DialogExResult result, void* context) {
|
||||
StorageSettings* app = context;
|
||||
|
||||
view_dispatcher_send_custom_event(app->view_dispatcher, result);
|
||||
}
|
||||
|
||||
void storage_settings_scene_unmounted_on_enter(void* context) {
|
||||
StorageSettings* app = context;
|
||||
FS_Error error = storage_sd_unmount(app->fs_api);
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_set_center_button_text(dialog_ex, "OK");
|
||||
dialog_ex_set_icon(dialog_ex, 72, 17, &I_DolphinCommon_56x48);
|
||||
|
||||
if(error == FSE_OK) {
|
||||
dialog_ex_set_header(dialog_ex, "SD Card Unmounted", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(dialog_ex, "You can remove\nSD card now.", 3, 22, AlignLeft, AlignTop);
|
||||
notification_message(app->notification, &sequence_blink_green_100);
|
||||
} else {
|
||||
dialog_ex_set_header(dialog_ex, "Cannot Unmount SD Card", 64, 3, AlignCenter, AlignTop);
|
||||
dialog_ex_set_text(dialog_ex, storage_error_get_desc(error), 3, 22, AlignLeft, AlignTop);
|
||||
notification_message(app->notification, &sequence_blink_red_100);
|
||||
}
|
||||
|
||||
dialog_ex_set_context(dialog_ex, app);
|
||||
dialog_ex_set_result_callback(dialog_ex, storage_settings_scene_unmounted_dialog_callback);
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, StorageSettingsViewDialogEx);
|
||||
}
|
||||
|
||||
bool storage_settings_scene_unmounted_on_event(void* context, SceneManagerEvent event) {
|
||||
StorageSettings* app = context;
|
||||
bool consumed = false;
|
||||
|
||||
if(event.type == SceneManagerEventTypeCustom) {
|
||||
switch(event.event) {
|
||||
case DialogExResultCenter:
|
||||
consumed = scene_manager_search_and_switch_to_previous_scene(
|
||||
app->scene_manager, StorageSettingsStart);
|
||||
break;
|
||||
}
|
||||
} else if(event.type == SceneManagerEventTypeBack) {
|
||||
consumed = true;
|
||||
}
|
||||
|
||||
return consumed;
|
||||
}
|
||||
|
||||
void storage_settings_scene_unmounted_on_exit(void* context) {
|
||||
StorageSettings* app = context;
|
||||
DialogEx* dialog_ex = app->dialog_ex;
|
||||
|
||||
dialog_ex_reset(dialog_ex);
|
||||
}
|
||||
76
applications/settings/storage_settings/storage_settings.c
Normal file
76
applications/settings/storage_settings/storage_settings.c
Normal file
@@ -0,0 +1,76 @@
|
||||
#include "storage_settings.h"
|
||||
|
||||
static bool storage_settings_custom_event_callback(void* context, uint32_t event) {
|
||||
furi_assert(context);
|
||||
StorageSettings* app = context;
|
||||
return scene_manager_handle_custom_event(app->scene_manager, event);
|
||||
}
|
||||
|
||||
static bool storage_settings_back_event_callback(void* context) {
|
||||
furi_assert(context);
|
||||
StorageSettings* app = context;
|
||||
return scene_manager_handle_back_event(app->scene_manager);
|
||||
}
|
||||
|
||||
static StorageSettings* storage_settings_alloc() {
|
||||
StorageSettings* app = malloc(sizeof(StorageSettings));
|
||||
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
app->fs_api = furi_record_open(RECORD_STORAGE);
|
||||
app->notification = furi_record_open(RECORD_NOTIFICATION);
|
||||
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
app->scene_manager = scene_manager_alloc(&storage_settings_scene_handlers, app);
|
||||
string_init(app->text_string);
|
||||
|
||||
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, storage_settings_custom_event_callback);
|
||||
view_dispatcher_set_navigation_event_callback(
|
||||
app->view_dispatcher, storage_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, StorageSettingsViewSubmenu, submenu_get_view(app->submenu));
|
||||
|
||||
app->dialog_ex = dialog_ex_alloc();
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher, StorageSettingsViewDialogEx, dialog_ex_get_view(app->dialog_ex));
|
||||
|
||||
scene_manager_next_scene(app->scene_manager, StorageSettingsStart);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
static void storage_settings_free(StorageSettings* app) {
|
||||
view_dispatcher_remove_view(app->view_dispatcher, StorageSettingsViewSubmenu);
|
||||
submenu_free(app->submenu);
|
||||
|
||||
view_dispatcher_remove_view(app->view_dispatcher, StorageSettingsViewDialogEx);
|
||||
dialog_ex_free(app->dialog_ex);
|
||||
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
scene_manager_free(app->scene_manager);
|
||||
|
||||
furi_record_close(RECORD_GUI);
|
||||
furi_record_close(RECORD_STORAGE);
|
||||
furi_record_close(RECORD_NOTIFICATION);
|
||||
|
||||
string_clear(app->text_string);
|
||||
|
||||
free(app);
|
||||
}
|
||||
|
||||
int32_t storage_settings_app(void* p) {
|
||||
UNUSED(p);
|
||||
StorageSettings* app = storage_settings_alloc();
|
||||
|
||||
view_dispatcher_run(app->view_dispatcher);
|
||||
|
||||
storage_settings_free(app);
|
||||
return 0;
|
||||
}
|
||||
47
applications/settings/storage_settings/storage_settings.h
Normal file
47
applications/settings/storage_settings/storage_settings.h
Normal file
@@ -0,0 +1,47 @@
|
||||
#pragma once
|
||||
#include <furi.h>
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/scene_manager.h>
|
||||
#include <notification/notification_messages.h>
|
||||
|
||||
#include <gui/modules/submenu.h>
|
||||
#include <gui/modules/dialog_ex.h>
|
||||
#include <gui/modules/popup.h>
|
||||
|
||||
#include <storage/storage.h>
|
||||
#include <storage/storage_sd_api.h>
|
||||
|
||||
#include "scenes/storage_settings_scene.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct {
|
||||
// records
|
||||
Gui* gui;
|
||||
NotificationApp* notification;
|
||||
Storage* fs_api;
|
||||
|
||||
// view managment
|
||||
SceneManager* scene_manager;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
|
||||
// view modules
|
||||
Submenu* submenu;
|
||||
DialogEx* dialog_ex;
|
||||
|
||||
// text
|
||||
string_t text_string;
|
||||
} StorageSettings;
|
||||
|
||||
typedef enum {
|
||||
StorageSettingsViewSubmenu,
|
||||
StorageSettingsViewDialogEx,
|
||||
} StorageSettingsView;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
9
applications/settings/system/application.fam
Normal file
9
applications/settings/system/application.fam
Normal file
@@ -0,0 +1,9 @@
|
||||
App(
|
||||
appid="system_settings",
|
||||
name="System",
|
||||
apptype=FlipperAppType.SETTINGS,
|
||||
entry_point="system_settings_app",
|
||||
requires=["gui"],
|
||||
stack_size=1 * 1024,
|
||||
order=70,
|
||||
)
|
||||
112
applications/settings/system/system_settings.c
Normal file
112
applications/settings/system/system_settings.c
Normal file
@@ -0,0 +1,112 @@
|
||||
#include "system_settings.h"
|
||||
#include <loader/loader.h>
|
||||
#include <lib/toolbox/value_index.h>
|
||||
|
||||
const char* const log_level_text[] = {
|
||||
"Default",
|
||||
"None",
|
||||
"Error",
|
||||
"Warning",
|
||||
"Info",
|
||||
"Debug",
|
||||
"Trace",
|
||||
};
|
||||
|
||||
const uint32_t log_level_value[] = {
|
||||
FuriLogLevelDefault,
|
||||
FuriLogLevelNone,
|
||||
FuriLogLevelError,
|
||||
FuriLogLevelWarn,
|
||||
FuriLogLevelInfo,
|
||||
FuriLogLevelDebug,
|
||||
FuriLogLevelTrace,
|
||||
};
|
||||
|
||||
static void log_level_changed(VariableItem* item) {
|
||||
// SystemSettings* app = variable_item_get_context(item);
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
variable_item_set_current_value_text(item, log_level_text[index]);
|
||||
furi_hal_rtc_set_log_level(log_level_value[index]);
|
||||
}
|
||||
|
||||
const char* const debug_text[] = {
|
||||
"OFF",
|
||||
"ON",
|
||||
};
|
||||
|
||||
static void debug_changed(VariableItem* item) {
|
||||
uint8_t index = variable_item_get_current_value_index(item);
|
||||
variable_item_set_current_value_text(item, debug_text[index]);
|
||||
if(index) {
|
||||
furi_hal_rtc_set_flag(FuriHalRtcFlagDebug);
|
||||
} else {
|
||||
furi_hal_rtc_reset_flag(FuriHalRtcFlagDebug);
|
||||
}
|
||||
loader_update_menu();
|
||||
}
|
||||
|
||||
static uint32_t system_settings_exit(void* context) {
|
||||
UNUSED(context);
|
||||
return VIEW_NONE;
|
||||
}
|
||||
|
||||
SystemSettings* system_settings_alloc() {
|
||||
SystemSettings* app = malloc(sizeof(SystemSettings));
|
||||
|
||||
// Load settings
|
||||
app->gui = furi_record_open(RECORD_GUI);
|
||||
|
||||
app->view_dispatcher = view_dispatcher_alloc();
|
||||
view_dispatcher_enable_queue(app->view_dispatcher);
|
||||
view_dispatcher_set_event_callback_context(app->view_dispatcher, app);
|
||||
|
||||
view_dispatcher_attach_to_gui(app->view_dispatcher, app->gui, ViewDispatcherTypeFullscreen);
|
||||
|
||||
VariableItem* item;
|
||||
uint8_t value_index;
|
||||
app->var_item_list = variable_item_list_alloc();
|
||||
|
||||
item = variable_item_list_add(
|
||||
app->var_item_list, "Log Level", COUNT_OF(log_level_text), log_level_changed, app);
|
||||
value_index = value_index_uint32(
|
||||
furi_hal_rtc_get_log_level(), log_level_value, COUNT_OF(log_level_text));
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, log_level_text[value_index]);
|
||||
|
||||
item = variable_item_list_add(
|
||||
app->var_item_list, "Debug", COUNT_OF(debug_text), debug_changed, app);
|
||||
value_index = furi_hal_rtc_is_flag_set(FuriHalRtcFlagDebug) ? 1 : 0;
|
||||
variable_item_set_current_value_index(item, value_index);
|
||||
variable_item_set_current_value_text(item, debug_text[value_index]);
|
||||
|
||||
view_set_previous_callback(
|
||||
variable_item_list_get_view(app->var_item_list), system_settings_exit);
|
||||
view_dispatcher_add_view(
|
||||
app->view_dispatcher,
|
||||
SystemSettingsViewVarItemList,
|
||||
variable_item_list_get_view(app->var_item_list));
|
||||
|
||||
view_dispatcher_switch_to_view(app->view_dispatcher, SystemSettingsViewVarItemList);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
||||
void system_settings_free(SystemSettings* app) {
|
||||
furi_assert(app);
|
||||
// Variable item list
|
||||
view_dispatcher_remove_view(app->view_dispatcher, SystemSettingsViewVarItemList);
|
||||
variable_item_list_free(app->var_item_list);
|
||||
// View dispatcher
|
||||
view_dispatcher_free(app->view_dispatcher);
|
||||
// Records
|
||||
furi_record_close(RECORD_GUI);
|
||||
free(app);
|
||||
}
|
||||
|
||||
int32_t system_settings_app(void* p) {
|
||||
UNUSED(p);
|
||||
SystemSettings* app = system_settings_alloc();
|
||||
view_dispatcher_run(app->view_dispatcher);
|
||||
system_settings_free(app);
|
||||
return 0;
|
||||
}
|
||||
18
applications/settings/system/system_settings.h
Normal file
18
applications/settings/system/system_settings.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include <furi.h>
|
||||
#include <furi_hal.h>
|
||||
|
||||
#include <gui/gui.h>
|
||||
#include <gui/view_dispatcher.h>
|
||||
#include <gui/modules/variable_item_list.h>
|
||||
|
||||
typedef struct {
|
||||
Gui* gui;
|
||||
ViewDispatcher* view_dispatcher;
|
||||
VariableItemList* var_item_list;
|
||||
} SystemSettings;
|
||||
|
||||
typedef enum {
|
||||
SystemSettingsViewVarItemList,
|
||||
} SystemSettingsView;
|
||||
Reference in New Issue
Block a user