Add startup warning and toggle

This commit is contained in:
i12bp8
2026-04-06 20:55:46 +02:00
parent ff619cfe63
commit cc918e5723
8 changed files with 181 additions and 4 deletions
+2
View File
@@ -22,11 +22,13 @@ App(
"scenes/tagtinker_scene_image_upload.c",
"scenes/tagtinker_scene_main_menu.c",
"scenes/tagtinker_scene_preset_list.c",
"scenes/tagtinker_scene_settings.c",
"scenes/tagtinker_scene_size_picker.c",
"scenes/tagtinker_scene_target_actions.c",
"scenes/tagtinker_scene_target_menu.c",
"scenes/tagtinker_scene_text_input.c",
"scenes/tagtinker_scene_transmit.c",
"scenes/tagtinker_scene_warning.c",
"views/numlock_input.c",
],
)
+6
View File
@@ -5,7 +5,9 @@
#include "tagtinker_scene.h"
void(*const tagtinker_scene_on_enter_handlers[])(void*) = {
tagtinker_scene_warning_on_enter,
tagtinker_scene_main_menu_on_enter,
tagtinker_scene_settings_on_enter,
tagtinker_scene_broadcast_menu_on_enter,
tagtinker_scene_broadcast_on_enter,
tagtinker_scene_target_menu_on_enter,
@@ -20,7 +22,9 @@ void(*const tagtinker_scene_on_enter_handlers[])(void*) = {
};
bool(*const tagtinker_scene_on_event_handlers[])(void*, SceneManagerEvent) = {
tagtinker_scene_warning_on_event,
tagtinker_scene_main_menu_on_event,
tagtinker_scene_settings_on_event,
tagtinker_scene_broadcast_menu_on_event,
tagtinker_scene_broadcast_on_event,
tagtinker_scene_target_menu_on_event,
@@ -35,7 +39,9 @@ bool(*const tagtinker_scene_on_event_handlers[])(void*, SceneManagerEvent) = {
};
void(*const tagtinker_scene_on_exit_handlers[])(void*) = {
tagtinker_scene_warning_on_exit,
tagtinker_scene_main_menu_on_exit,
tagtinker_scene_settings_on_exit,
tagtinker_scene_broadcast_menu_on_exit,
tagtinker_scene_broadcast_on_exit,
tagtinker_scene_target_menu_on_exit,
+10
View File
@@ -7,7 +7,9 @@
#include <gui/scene_manager.h>
typedef enum {
TagTinkerSceneWarning,
TagTinkerSceneMainMenu,
TagTinkerSceneSettings,
TagTinkerSceneBroadcastMenu,
TagTinkerSceneBroadcast,
TagTinkerSceneTargetMenu,
@@ -23,10 +25,18 @@ typedef enum {
} TagTinkerScene;
/* Scene handler declarations */
void tagtinker_scene_warning_on_enter(void* ctx);
bool tagtinker_scene_warning_on_event(void* ctx, SceneManagerEvent event);
void tagtinker_scene_warning_on_exit(void* ctx);
void tagtinker_scene_main_menu_on_enter(void* ctx);
bool tagtinker_scene_main_menu_on_event(void* ctx, SceneManagerEvent event);
void tagtinker_scene_main_menu_on_exit(void* ctx);
void tagtinker_scene_settings_on_enter(void* ctx);
bool tagtinker_scene_settings_on_event(void* ctx, SceneManagerEvent event);
void tagtinker_scene_settings_on_exit(void* ctx);
void tagtinker_scene_broadcast_menu_on_enter(void* ctx);
bool tagtinker_scene_broadcast_menu_on_event(void* ctx, SceneManagerEvent event);
void tagtinker_scene_broadcast_menu_on_exit(void* ctx);
+8 -3
View File
@@ -7,6 +7,7 @@
enum {
MainMenuBroadcast,
MainMenuTargetESL,
MainMenuSettings,
MainMenuAndroid,
MainMenuAbout,
};
@@ -23,9 +24,10 @@ void tagtinker_scene_main_menu_on_enter(void* ctx) {
submenu_set_header(app->submenu, TAGTINKER_DISPLAY_NAME " v" TAGTINKER_VERSION);
submenu_add_item(app->submenu, "Broadcast Tag", MainMenuBroadcast, main_menu_cb, app);
submenu_add_item(app->submenu, "Target Tag", MainMenuTargetESL, main_menu_cb, app);
submenu_add_item(app->submenu, "Android App", MainMenuAndroid, main_menu_cb, app);
submenu_add_item(app->submenu, "About", MainMenuAbout, main_menu_cb, app);
submenu_add_item(app->submenu, "Target Tag", MainMenuTargetESL, main_menu_cb, app);
submenu_add_item(app->submenu, "Settings", MainMenuSettings, main_menu_cb, app);
submenu_add_item(app->submenu, "Android App", MainMenuAndroid, main_menu_cb, app);
submenu_add_item(app->submenu, "About", MainMenuAbout, main_menu_cb, app);
submenu_set_selected_item(
app->submenu,
@@ -47,6 +49,9 @@ bool tagtinker_scene_main_menu_on_event(void* ctx, SceneManagerEvent event) {
case MainMenuTargetESL:
scene_manager_next_scene(app->scene_manager, TagTinkerSceneTargetMenu);
return true;
case MainMenuSettings:
scene_manager_next_scene(app->scene_manager, TagTinkerSceneSettings);
return true;
case MainMenuAndroid:
/* state=1 tells About scene to show Android teaser */
scene_manager_set_scene_state(app->scene_manager, TagTinkerSceneAbout, 1);
+50
View File
@@ -0,0 +1,50 @@
/*
* Settings scene
*/
#include "../tagtinker_app.h"
enum {
SettingsItemStartupWarning,
};
static const char* settings_toggle_labels[] = {"Off", "On"};
static void startup_warning_changed(VariableItem* item) {
TagTinkerApp* app = variable_item_get_context(item);
uint8_t index = variable_item_get_current_value_index(item);
app->show_startup_warning = (index == 1);
variable_item_set_current_value_text(item, settings_toggle_labels[index]);
if(!tagtinker_settings_save(app)) {
FURI_LOG_W(TAGTINKER_TAG, "Failed to save settings");
}
}
void tagtinker_scene_settings_on_enter(void* ctx) {
TagTinkerApp* app = ctx;
VariableItemList* list = app->var_item_list;
variable_item_list_reset(list);
VariableItem* item = variable_item_list_add(
list, "Startup Warning", 2, startup_warning_changed, app);
variable_item_set_current_value_index(item, app->show_startup_warning ? 1 : 0);
variable_item_set_current_value_text(
item, settings_toggle_labels[app->show_startup_warning ? 1 : 0]);
variable_item_list_set_selected_item(list, SettingsItemStartupWarning);
view_dispatcher_switch_to_view(app->view_dispatcher, TagTinkerViewVarItemList);
}
bool tagtinker_scene_settings_on_event(void* ctx, SceneManagerEvent event) {
UNUSED(ctx);
UNUSED(event);
return false;
}
void tagtinker_scene_settings_on_exit(void* ctx) {
TagTinkerApp* app = ctx;
variable_item_list_reset(app->var_item_list);
}
+60
View File
@@ -0,0 +1,60 @@
/*
* Startup warning scene
*/
#include "../tagtinker_app.h"
enum {
TagTinkerStartupWarningContinue,
};
static const char* startup_warning_text =
"\ec\e#TagTinker - Research Tool\n"
"\n"
"This is an educational research tool for infrared electronic shelf label "
"(ESL) protocols.\n"
"It implements publicly documented signaling for tags commonly used in "
"retail (often referred to as Pricer-style ESLs).\n"
"Use ONLY on tags you personally own or have explicit permission to test.\n"
"Using this tool on retail store systems without authorization may violate "
"laws on fraud or interference with business operations. You are solely "
"responsible for your actions. Misuse is not endorsed.\n"
"\n"
"\ecPress OK to continue.";
static void startup_warning_button_cb(GuiButtonType result, InputType type, void* context) {
if(type != InputTypeShort || result != GuiButtonTypeCenter) return;
TagTinkerApp* app = context;
view_dispatcher_send_custom_event(
app->view_dispatcher, TagTinkerStartupWarningContinue);
}
void tagtinker_scene_warning_on_enter(void* ctx) {
TagTinkerApp* app = ctx;
widget_reset(app->widget);
widget_add_text_scroll_element(app->widget, 0, 0, 128, 52, startup_warning_text);
widget_add_button_element(
app->widget, GuiButtonTypeCenter, "OK", startup_warning_button_cb, app);
view_dispatcher_switch_to_view(app->view_dispatcher, TagTinkerViewWidget);
}
bool tagtinker_scene_warning_on_event(void* ctx, SceneManagerEvent event) {
TagTinkerApp* app = ctx;
if(event.type == SceneManagerEventTypeCustom &&
event.event == TagTinkerStartupWarningContinue) {
scene_manager_search_and_switch_to_another_scene(
app->scene_manager, TagTinkerSceneMainMenu);
return true;
}
return false;
}
void tagtinker_scene_warning_on_exit(void* ctx) {
TagTinkerApp* app = ctx;
widget_reset(app->widget);
}
+40 -1
View File
@@ -29,6 +29,42 @@ static bool custom_event_cb(void* ctx, uint32_t event) {
extern const SceneManagerHandlers tagtinker_scene_handlers;
void tagtinker_settings_load(TagTinkerApp* app) {
app->show_startup_warning = true;
Storage* storage = furi_record_open(RECORD_STORAGE);
File* file = storage_file_alloc(storage);
if(storage_file_open(file, APP_DATA_PATH("settings.txt"), FSAM_READ, FSOM_OPEN_EXISTING)) {
char value = '1';
if(storage_file_read(file, &value, 1) == 1) {
app->show_startup_warning = (value != '0');
}
storage_file_close(file);
}
storage_file_free(file);
furi_record_close(RECORD_STORAGE);
}
bool tagtinker_settings_save(const TagTinkerApp* app) {
Storage* storage = furi_record_open(RECORD_STORAGE);
storage_common_mkdir(storage, APP_DATA_PATH(""));
File* file = storage_file_alloc(storage);
bool ok = false;
if(storage_file_open(file, APP_DATA_PATH("settings.txt"), FSAM_WRITE, FSOM_CREATE_ALWAYS)) {
const char value = app->show_startup_warning ? '1' : '0';
ok = (storage_file_write(file, &value, 1) == 1);
storage_file_close(file);
}
storage_file_free(file);
furi_record_close(RECORD_STORAGE);
return ok;
}
void tagtinker_targets_load(TagTinkerApp* app) {
app->target_count = 0;
@@ -127,6 +163,7 @@ static TagTinkerApp* app_alloc(void) {
app->invert_text = false;
strcpy(app->text_input_buf, "TagTinker");
app->selected_target = -1;
tagtinker_settings_load(app);
tagtinker_targets_load(app);
/* Scene manager */
@@ -236,7 +273,9 @@ static void app_free(TagTinkerApp* app) {
int32_t tagtinker_app_main(void* p) {
UNUSED(p);
TagTinkerApp* app = app_alloc();
scene_manager_next_scene(app->scene_manager, TagTinkerSceneMainMenu);
scene_manager_next_scene(
app->scene_manager,
app->show_startup_warning ? TagTinkerSceneWarning : TagTinkerSceneMainMenu);
view_dispatcher_run(app->view_dispatcher);
app_free(app);
return 0;
+5
View File
@@ -86,6 +86,7 @@ struct TagTinkerApp {
uint16_t repeats;
bool forever;
bool tx_spam;
bool show_startup_warning;
/* Current target */
char barcode[TAGTINKER_BC_LEN + 1];
@@ -140,6 +141,8 @@ struct TagTinkerApp {
typedef enum {
TagTinkerMenuBroadcast,
TagTinkerMenuTargetESL,
TagTinkerMenuSettings,
TagTinkerMenuAndroid,
TagTinkerMenuAbout,
} TagTinkerMainMenuItem;
@@ -156,5 +159,7 @@ typedef enum {
TagTinkerTargetPingFlash,
} TagTinkerTargetActionItem;
void tagtinker_settings_load(TagTinkerApp* app);
bool tagtinker_settings_save(const TagTinkerApp* app);
void tagtinker_targets_load(TagTinkerApp* app);
bool tagtinker_targets_save(const TagTinkerApp* app);