Add card acceptance animation

This commit is contained in:
Edith Boles
2026-03-02 01:53:39 -08:00
parent e0d0728b12
commit 260c9c7a94
12 changed files with 1795 additions and 95 deletions

2
.gitignore vendored
View File

@@ -2,6 +2,6 @@ bin/
obj/ obj/
.cache .cache
.build .build
.config.old
build.log build.log
include include
.config.old

BIN
hop.xcf Normal file

Binary file not shown.

14
inc/idle.h Normal file
View File

@@ -0,0 +1,14 @@
/**********************************************************
* File: idle.h
*
* Description: Idle screen for standby
*********************************************************/
#ifndef IDLE_H_CGT5FQUY
#define IDLE_H_CGT5FQUY
#include "lvgl/lvgl.h" // IWYU pragma: keep
void screen_idle_create(lv_obj_t *screen);
void screen_idle_update();
#endif /* end of include guard: IDLE_H_CGT5FQUY */

168
src/idle.c Normal file
View File

@@ -0,0 +1,168 @@
/**********************************************************
* File: idle.c
*
* Description: Idle screen for standby
*********************************************************/
#include "lvgl/lvgl.h" // IWYU pragma: keep
#include "lvgl/src/misc/lv_anim.h"
#include "lvgl/src/widgets/label/lv_label.h"
#include <time.h>
#include <unistd.h>
#define ARROW_DURATION 395
#define CARDS_DURATION 4000
#define CARDS_RATE 3.0
#define CARDS_MID 0.5
#define CARDS_DELAY 0.09
#define WHITE lv_color_hex(0xffffff)
LV_FONT_DECLARE(montserrat_15);
LV_FONT_DECLARE(dejavu_28);
LV_FONT_DECLARE(dejavu_bold_10);
LV_FONT_DECLARE(dejavu_cbold_52);
LV_IMG_DECLARE(hop_arrow);
LV_IMG_DECLARE(hop_logo);
LV_IMG_DECLARE(hop_cards);
static lv_anim_t arrow_anim_template;
static lv_anim_t *running_arrow_anim;
static lv_anim_t cards_anim_template;
static lv_anim_t *running_cards_anim;
lv_obj_t *label_time;
lv_obj_t *label_date;
lv_obj_t *label_tap;
lv_obj_t *label_sku;
lv_obj_t *label_contactless;
lv_obj_t *img_arrow;
lv_obj_t *img_logo;
lv_obj_t *img_cards;
time_t curr_time;
struct tm *local_time;
char buf[100];
double clamp(double d, double min, double max)
{
const double t = d < min ? min : d;
return t > max ? max : t;
}
void set_opa(void *var, int32_t value)
{
lv_obj_t *obj = (lv_obj_t *)var;
lv_obj_set_style_image_opa(obj, value, 0);
}
void cards_anim_cb(void *var, int32_t value)
{
double progress = (double)value / 0x7fff;
double prompt_opa = progress - (CARDS_MID - CARDS_DELAY / 2);
prompt_opa *= CARDS_RATE;
prompt_opa = clamp(prompt_opa, 0.0, 1.0) * 255;
double cards_opa = -progress + (CARDS_MID - CARDS_DELAY / 2);
cards_opa *= CARDS_RATE;
cards_opa = clamp(cards_opa, 0.0, 1.0) * 255;
lv_obj_set_style_text_opa(label_tap, (int32_t)prompt_opa, 0);
lv_obj_set_style_image_opa(img_cards, (int32_t)cards_opa, 0);
lv_obj_set_style_text_opa(label_contactless, (int32_t)cards_opa, 0);
}
void screen_idle_create(lv_obj_t *screen)
{
/*Change the active screen's background color*/
lv_obj_set_style_bg_color(screen, lv_color_hex(0), LV_PART_MAIN);
// hop logo
img_logo = lv_img_create(screen);
lv_img_set_src(img_logo, &hop_logo);
lv_obj_align(img_logo, LV_ALIGN_CENTER, 0, -98);
// flickering arrow
img_arrow = lv_img_create(screen);
lv_img_set_src(img_arrow, &hop_arrow);
lv_obj_align(img_arrow, LV_ALIGN_CENTER, 0, 155);
lv_obj_set_style_img_opa(img_arrow, 100, 0);
lv_anim_init(&arrow_anim_template);
lv_anim_set_exec_cb(&arrow_anim_template, set_opa);
lv_anim_set_values(&arrow_anim_template, 0, 255);
lv_anim_set_duration(&arrow_anim_template, ARROW_DURATION);
lv_anim_set_path_cb(&arrow_anim_template, lv_anim_path_ease_out);
lv_anim_set_reverse_duration(&arrow_anim_template, ARROW_DURATION);
lv_anim_set_repeat_count(&arrow_anim_template, LV_ANIM_REPEAT_INFINITE);
lv_anim_set_var(&arrow_anim_template, img_arrow);
running_arrow_anim = lv_anim_start(&arrow_anim_template);
// tap prompt
label_tap = lv_label_create(screen);
lv_label_set_text(label_tap, "Tap card or phone below");
lv_obj_set_style_text_font(label_tap, &dejavu_cbold_52, 0);
lv_obj_set_style_text_color(label_tap, WHITE, 0);
lv_obj_align(label_tap, LV_ALIGN_CENTER, 0, 83);
// card acceptance logos
img_cards = lv_img_create(screen);
lv_img_set_src(img_cards, &hop_cards);
lv_obj_align(img_cards, LV_ALIGN_CENTER, 0, 75);
// contactless payments note
label_contactless = lv_label_create(screen);
lv_label_set_text(label_contactless, "Contactless payment only");
lv_obj_set_style_text_font(label_contactless, &montserrat_15, 0);
lv_obj_set_style_text_color(label_contactless, WHITE, 0);
lv_obj_align(label_contactless, LV_ALIGN_CENTER, 0, 118);
// animation for tap prompt/card acceptance
lv_anim_init(&cards_anim_template);
lv_anim_set_exec_cb(&cards_anim_template, cards_anim_cb);
lv_anim_set_values(&cards_anim_template, 0, 0x7fff);
lv_anim_set_duration(&cards_anim_template, CARDS_DURATION);
lv_anim_set_path_cb(&cards_anim_template, lv_anim_path_linear);
lv_anim_set_reverse_duration(&cards_anim_template, CARDS_DURATION);
lv_anim_set_repeat_count(&cards_anim_template, LV_ANIM_REPEAT_INFINITE);
lv_anim_set_var(&cards_anim_template, label_contactless);
running_cards_anim = lv_anim_start(&cards_anim_template);
// device number at bottom
label_sku = lv_label_create(screen);
lv_label_set_text(label_sku, "DEMO-DEV-LVGL");
lv_obj_set_style_text_font(label_sku, &dejavu_bold_10, 0);
lv_obj_set_style_text_color(label_sku, WHITE, 0);
lv_obj_align(label_sku, LV_ALIGN_CENTER, 0, 233);
// date in bottom left
label_date = lv_label_create(screen);
lv_label_set_text(label_date, "01-01-99");
lv_obj_set_style_text_font(label_date, &dejavu_28, 0);
lv_obj_set_style_text_color(label_date, WHITE, 0);
lv_obj_align(label_date, LV_ALIGN_CENTER, -275, 226);
// time in bottom right
label_time = lv_label_create(screen);
lv_label_set_text(label_time, "12:59 a.m.");
lv_obj_set_style_text_font(label_time, &dejavu_28, 0);
lv_obj_set_style_text_color(label_time, WHITE, 0);
lv_obj_align(label_time, LV_ALIGN_CENTER, 275, 226);
}
void screen_idle_update()
{
time(&curr_time);
local_time = localtime(&curr_time);
strftime(buf, 100, "%m-%d-%y", local_time);
lv_label_set_text(label_date, buf);
strftime(buf, 90, "%l:%M %P", local_time);
int i = 0;
while (buf[i])
i++;
if (i > 0) {
buf[i - 1] = '.';
buf[i] = 'm';
buf[i + 1] = '.';
buf[i + 2] = '\0';
}
lv_label_set_text(label_time, buf);
}

View File

@@ -1,88 +1,12 @@
#include "lvgl/lvgl.h" // IWYU pragma: keep #include "lvgl/lvgl.h" // IWYU pragma: keep
#include "lvgl/src/misc/lv_anim.h"
#include "lvgl/src/widgets/label/lv_label.h"
#include <time.h>
#include <unistd.h> #include <unistd.h>
#include "idle.h"
#define ARROW_DELAY 395
LV_FONT_DECLARE(dejavu_28);
LV_FONT_DECLARE(dejavu_bold_10);
LV_FONT_DECLARE(dejavu_cbold_52);
LV_IMG_DECLARE(hop_arrow);
LV_IMG_DECLARE(hop_logo);
static lv_anim_t anim_template;
static lv_anim_t *running_anim;
lv_display_t *display; lv_display_t *display;
lv_obj_t *label_time; uint32_t idle_time;
lv_obj_t *label_date;
void set_opa(void *var, int32_t value)
{
lv_obj_t *obj = (lv_obj_t *)var;
lv_obj_set_style_image_opa(obj, value, 0);
}
void create_screen()
{
/*Change the active screen's background color*/
lv_obj_set_style_bg_color(lv_screen_active(), lv_color_hex(0),
LV_PART_MAIN);
lv_obj_t *logo = lv_img_create(lv_screen_active());
lv_img_set_src(logo, &hop_logo);
lv_obj_align(logo, LV_ALIGN_CENTER, 0, -98);
lv_obj_t *arrow = lv_img_create(lv_screen_active());
lv_img_set_src(arrow, &hop_arrow);
lv_obj_align(arrow, LV_ALIGN_CENTER, 0, 155);
lv_obj_set_style_img_opa(arrow, 100, 0);
lv_anim_init(&anim_template);
lv_anim_set_exec_cb(&anim_template, set_opa);
lv_anim_set_values(&anim_template, 0, 255);
lv_anim_set_duration(&anim_template, ARROW_DELAY);
lv_anim_set_path_cb(&anim_template, lv_anim_path_ease_out);
lv_anim_set_reverse_duration(&anim_template, ARROW_DELAY);
lv_anim_set_repeat_count(&anim_template, LV_ANIM_REPEAT_INFINITE);
lv_anim_set_var(&anim_template, arrow);
running_anim = lv_anim_start(&anim_template);
lv_obj_t *label_tap = lv_label_create(lv_screen_active());
lv_label_set_text(label_tap, "Tap card or phone below");
lv_obj_set_style_text_font(label_tap, &dejavu_cbold_52, 0);
lv_obj_set_style_text_color(label_tap, lv_color_hex(0xffffff), 0);
lv_obj_align(label_tap, LV_ALIGN_CENTER, 0, 83);
lv_obj_t *label_sku = lv_label_create(lv_screen_active());
lv_label_set_text(label_sku, "DEMO-DEV-LVGL");
lv_obj_set_style_text_font(label_sku, &dejavu_bold_10, 0);
lv_obj_set_style_text_color(label_sku, lv_color_hex(0xffffff), 0);
lv_obj_align(label_sku, LV_ALIGN_CENTER, 0, 233);
label_date = lv_label_create(lv_screen_active());
lv_label_set_text(label_date, "01-01-99");
lv_obj_set_style_text_font(label_date, &dejavu_28, 0);
lv_obj_set_style_text_color(label_date, lv_color_hex(0xffffff), 0);
lv_obj_align(label_date, LV_ALIGN_CENTER, -275, 226);
label_time = lv_label_create(lv_screen_active());
lv_label_set_text(label_time, "12:59 a.m.");
lv_obj_set_style_text_font(label_time, &dejavu_28, 0);
lv_obj_set_style_text_color(label_time, lv_color_hex(0xffffff), 0);
lv_obj_align(label_time, LV_ALIGN_CENTER, 275, 226);
}
int main(int argc, char *argv[]) int main(int argc, char *argv[])
{ {
uint32_t idle_time;
time_t curr_time;
struct tm *local_time;
char buf[100];
lv_init(); lv_init();
#ifdef LV_TARGET_FB #ifdef LV_TARGET_FB
display = lv_linux_fbdev_create(); display = lv_linux_fbdev_create();
@@ -91,26 +15,12 @@ int main(int argc, char *argv[])
display = lv_x11_window_create("LVGL X11 Simulation", 800, 480); display = lv_x11_window_create("LVGL X11 Simulation", 800, 480);
#endif #endif
create_screen(); screen_idle_create(lv_screen_active());
while (true) { while (true) {
/* Returns the time to the next timer execution */ /* Returns the time to the next timer execution */
idle_time = lv_timer_handler(); idle_time = lv_timer_handler();
time(&curr_time); screen_idle_update();
local_time = localtime(&curr_time);
strftime(buf, 100, "%m-%d-%y", local_time);
lv_label_set_text(label_date, buf);
strftime(buf, 90, "%l:%M %P", local_time);
int i = 0;
while (buf[i])
i++;
if (i > 0) {
buf[i - 1] = '.';
buf[i] = 'm';
buf[i + 1] = '.';
buf[i + 2] = '\0';
}
lv_label_set_text(label_time, buf);
usleep(idle_time * 1000); usleep(idle_time * 1000);
} }
} }

92
src/res/hop_cards.c Normal file

File diff suppressed because one or more lines are too long

1516
src/res/montserrat_15.c Normal file

File diff suppressed because it is too large Load Diff