Skip to content

Commit

Permalink
UI alert + long press to exit.
Browse files Browse the repository at this point in the history
  • Loading branch information
antirez committed Jan 19, 2023
1 parent 86c5c71 commit c93ae3c
Show file tree
Hide file tree
Showing 4 changed files with 95 additions and 22 deletions.
21 changes: 18 additions & 3 deletions app.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,9 @@ static void render_callback(Canvas *const canvas, void *ctx) {
case ViewDirectSampling: render_view_direct_sampling(canvas,app); break;
default: furi_crash(TAG "Invalid view selected"); break;
}

/* Draw the alert box if set. */
ui_draw_alert_if_needed(canvas, app);
}

/* Here all we do is putting the events into the queue that will be handled
Expand Down Expand Up @@ -106,6 +109,7 @@ static void app_switch_view(ProtoViewApp *app, ProtoViewCurrentView switchto) {
* the main thing. */
app->current_subview[old] = 0;
memset(app->view_privdata,0,PROTOVIEW_VIEW_PRIVDATA_LEN);
ui_dismiss_alert(app);
}

/* Allocate the application state and initialize a number of stuff.
Expand All @@ -132,6 +136,7 @@ ProtoViewApp* protoview_app_alloc() {
app->view_dispatcher = NULL;
app->text_input = NULL;
app->show_text_input = false;
app->alert_dismiss_time = 0;
app->current_view = ViewRawPulses;
for (int j = 0; j < ViewLast; j++) app->current_subview[j] = 0;
app->direct_sampling_enabled = false;
Expand Down Expand Up @@ -269,17 +274,27 @@ int32_t protoview_app_entry(void* p) {
if (input.type == InputTypeShort &&
input.key == InputKeyBack)
{
/* Exit the app. */
if (app->current_view != ViewRawPulses) {
/* If this is not the main app view, go there. */
app_switch_view(app,ViewRawPulses);
} else {
/* If we are in the main app view, warn the user
* they needs to long press to really quit. */
ui_show_alert(app,"Long press to exit",1000);
}
} else if (input.type == InputTypeLong &&
input.key == InputKeyBack)
{
app->running = 0;
} else if (input.type == InputTypeShort &&
input.key == InputKeyRight &&
get_current_subview(app) == 0)
ui_get_current_subview(app) == 0)
{
/* Go to the next view. */
app_switch_view(app,ViewGoNext);
} else if (input.type == InputTypeShort &&
input.key == InputKeyLeft &&
get_current_subview(app) == 0)
ui_get_current_subview(app) == 0)
{
/* Go to the previous view. */
app_switch_view(app,ViewGoPrev);
Expand Down
24 changes: 18 additions & 6 deletions app.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ typedef struct ProtoViewMsgInfo {
} ProtoViewMsgInfo;

/* Our main application context. */
#define ALERT_MAX_LEN 32
struct ProtoViewApp {
/* GUI */
Gui *gui;
Expand All @@ -125,6 +126,8 @@ struct ProtoViewApp {
ProtoViewCurrentView current_view; /* Active left-right view ID. */
int current_subview[ViewLast]; /* Active up-down subview ID. */
FuriMessageQueue *event_queue; /* Keypress events go here. */

/* Input text state. */
ViewDispatcher *view_dispatcher; /* Used only when we want to show
the text_input view for a moment.
Otherwise it is set to null. */
Expand All @@ -134,6 +137,12 @@ struct ProtoViewApp {
uint32_t text_input_buffer_len;
void (*text_input_done_callback)(void*);

/* Alert state. */
uint32_t alert_dismiss_time; /* Millisecond when the alert will be
no longer shown. Or zero if the alert
is currently not set at all. */
char alert_text[ALERT_MAX_LEN]; /* Alert content. */

/* Radio related. */
ProtoViewTxRx *txrx; /* Radio state. */
SubGhzSetting *setting; /* A list of valid frequencies. */
Expand Down Expand Up @@ -222,13 +231,16 @@ void view_exit_direct_sampling(ProtoViewApp *app);
void view_exit_settings(ProtoViewApp *app);

/* ui.c */
int get_current_subview(ProtoViewApp *app);
void show_available_subviews(Canvas *canvas, ProtoViewApp *app, int last_subview);
bool process_subview_updown(ProtoViewApp *app, InputEvent input, int last_subview);
void canvas_draw_str_with_border(Canvas* canvas, uint8_t x, uint8_t y, const char* str, Color text_color, Color border_color);
void show_keyboard(ProtoViewApp *app, char *buffer, uint32_t buflen,
int ui_get_current_subview(ProtoViewApp *app);
void ui_show_available_subviews(Canvas *canvas, ProtoViewApp *app, int last_subview);
bool ui_process_subview_updown(ProtoViewApp *app, InputEvent input, int last_subview);
void ui_show_keyboard(ProtoViewApp *app, char *buffer, uint32_t buflen,
void (*done_callback)(void*));
void dismiss_keyboard(ProtoViewApp *app);
void ui_dismiss_keyboard(ProtoViewApp *app);
void ui_show_alert(ProtoViewApp *app, const char *text, uint32_t ttl);
void ui_dismiss_alert(ProtoViewApp *app);
void ui_draw_alert_if_needed(Canvas *canvas, ProtoViewApp *app);
void canvas_draw_str_with_border(Canvas* canvas, uint8_t x, uint8_t y, const char* str, Color text_color, Color border_color);

/* crc.c */
uint8_t crc8(const uint8_t *data, size_t len, uint8_t init, uint8_t poly);
56 changes: 49 additions & 7 deletions ui.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,17 +10,17 @@

/* Return the ID of the currently selected subview, of the current
* view. */
int get_current_subview(ProtoViewApp *app) {
int ui_get_current_subview(ProtoViewApp *app) {
return app->current_subview[app->current_view];
}

/* Called by view rendering callback that has subviews, to show small triangles
* facing down/up if there are other subviews the user can access with up
* and down. */
void show_available_subviews(Canvas *canvas, ProtoViewApp *app,
void ui_show_available_subviews(Canvas *canvas, ProtoViewApp *app,
int last_subview)
{
int subview = get_current_subview(app);
int subview = ui_get_current_subview(app);
if (subview != 0)
canvas_draw_triangle(canvas,120,5,8,5,CanvasDirectionBottomToTop);
if (subview != last_subview-1)
Expand All @@ -30,8 +30,8 @@ void show_available_subviews(Canvas *canvas, ProtoViewApp *app,
/* Handle up/down keys when we are in a subview. If the function catched
* such keypress, it returns true, so that the actual view input callback
* knows it can just return ASAP without doing anything. */
bool process_subview_updown(ProtoViewApp *app, InputEvent input, int last_subview) {
int subview = get_current_subview(app);
bool ui_process_subview_updown(ProtoViewApp *app, InputEvent input, int last_subview) {
int subview = ui_get_current_subview(app);
if (input.type == InputTypePress) {
if (input.key == InputKeyUp) {
if (subview != 0)
Expand Down Expand Up @@ -62,7 +62,7 @@ bool process_subview_updown(ProtoViewApp *app, InputEvent input, int last_subvie
*
* Note: if the buffer is not a null-termined zero string, what it contains will
* be used as initial input for the user. */
void show_keyboard(ProtoViewApp *app, char *buffer, uint32_t buflen,
void ui_show_keyboard(ProtoViewApp *app, char *buffer, uint32_t buflen,
void (*done_callback)(void*))
{
app->show_text_input = true;
Expand All @@ -71,10 +71,52 @@ void show_keyboard(ProtoViewApp *app, char *buffer, uint32_t buflen,
app->text_input_done_callback = done_callback;
}

void dismiss_keyboard(ProtoViewApp *app) {
void ui_dismiss_keyboard(ProtoViewApp *app) {
view_dispatcher_stop(app->view_dispatcher);
}

/* ================================= Alert ================================== */

/* Set an alert message to be shown over any currently active view, for
* the specified amount of time of 'ttl' milliseconds. */
void ui_show_alert(ProtoViewApp *app, const char *text, uint32_t ttl) {
app->alert_dismiss_time = furi_get_tick() + furi_ms_to_ticks(ttl);
snprintf(app->alert_text,ALERT_MAX_LEN,"%s",text);
}

/* Cancel the alert before its time has elapsed. */
void ui_dismiss_alert(ProtoViewApp *app) {
app->alert_dismiss_time = 0;
}

/* Show the alert if an alert is set. This is called after the currently
* active view displayed its stuff, so we overwrite the screen with the
* alert message. */
void ui_draw_alert_if_needed(Canvas *canvas, ProtoViewApp *app) {
if (app->alert_dismiss_time == 0) {
/* No active alert. */
return;
} else if (app->alert_dismiss_time < furi_get_tick()) {
/* Alert just expired. */
ui_dismiss_alert(app);
return;
}

/* Show the alert. A box with black border and a text inside. */
canvas_set_font(canvas, FontPrimary);
uint8_t w = canvas_string_width(canvas, app->alert_text);
uint8_t h = 8; // Font height.
uint8_t text_x = 64-(w/2);
uint8_t text_y = 32+4;
uint8_t padding = 3;
canvas_set_color(canvas,ColorBlack);
canvas_draw_box(canvas,text_x-padding,text_y-padding-h,w+padding*2,h+padding*2);
canvas_set_color(canvas,ColorWhite);
canvas_draw_box(canvas,text_x-padding+1,text_y-padding-h+1,w+padding*2-2,h+padding*2-2);
canvas_set_color(canvas,ColorBlack);
canvas_draw_str(canvas,text_x,text_y,app->alert_text);
}

/* =========================== Canvas extensions ============================ */

void canvas_draw_str_with_border(Canvas* canvas, uint8_t x, uint8_t y, const char* str, Color text_color, Color border_color)
Expand Down
16 changes: 10 additions & 6 deletions view_info.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ void render_view_info(Canvas *const canvas, ProtoViewApp *app) {
return;
}

show_available_subviews(canvas,app,SubViewInfoLast);
ui_show_available_subviews(canvas,app,SubViewInfoLast);
switch(app->current_subview[app->current_view]) {
case SubViewInfoMain: render_subview_main(canvas,app); break;
case SubViewInfoSave: render_subview_save(canvas,app); break;
Expand All @@ -115,7 +115,7 @@ void text_input_done_callback(void* context) {
furi_string_free(save_path);

free(privdata->filename);
dismiss_keyboard(app);
ui_dismiss_keyboard(app);
}

/* Replace all the occurrences of character c1 with c2 in the specified
Expand Down Expand Up @@ -253,9 +253,13 @@ void notify_signal_sent(ProtoViewApp *app) {

/* Handle input for the info view. */
void process_input_info(ProtoViewApp *app, InputEvent input) {
if (process_subview_updown(app,input,SubViewInfoLast)) return;
/* If we don't have a decoded signal, we don't allow to go up/down
* in the subviews: they are only useful when a loaded signal. */
if (app->signal_decoded &&
ui_process_subview_updown(app,input,SubViewInfoLast)) return;

InfoViewPrivData *privdata = app->view_privdata;
int subview = get_current_subview(app);
int subview = ui_get_current_subview(app);

/* Main subview. */
if (subview == SubViewInfoMain) {
Expand All @@ -274,8 +278,8 @@ void process_input_info(ProtoViewApp *app, InputEvent input) {
{
privdata->filename = malloc(SAVE_FILENAME_LEN);
set_signal_random_filename(app,privdata->filename,SAVE_FILENAME_LEN);
show_keyboard(app, privdata->filename, SAVE_FILENAME_LEN,
text_input_done_callback);
ui_show_keyboard(app, privdata->filename, SAVE_FILENAME_LEN,
text_input_done_callback);
} else if (input.type == InputTypeShort && input.key == InputKeyOk) {
SendSignalCtx send_state;
send_signal_init(&send_state,app);
Expand Down

0 comments on commit c93ae3c

Please sign in to comment.