@@ -179,23 +179,23 @@ void startArmFailIconFlash() {
179179static void critical_border_flash_timer_cb (lv_timer_t * timer) {
180180 // This callback runs within the LVGL task handler, so no mutex needed here.
181181 if (critical_border != NULL ) {
182- // Toggle visibility: 300ms on, 700ms off
183- bool is_on = !lv_obj_has_flag (critical_border, LV_OBJ_FLAG_HIDDEN);
184- if (is_on) {
185- lv_obj_add_flag (critical_border, LV_OBJ_FLAG_HIDDEN);
186- // Invalidate the border area to ensure clean redraw
187- lv_obj_invalidate (critical_border);
182+ // Toggle opacity: 300ms on (opaque), 700ms off (transparent)
183+ uint8_t current_opa = lv_obj_get_style_border_opa (critical_border, LV_PART_MAIN);
184+ if (current_opa == LV_OPA_100) {
185+ lv_obj_set_style_border_opa (critical_border, LV_OPA_0, LV_PART_MAIN);
188186 lv_timer_set_period (timer, 700 ); // Off duration
187+ // Invalidate entire screen when hiding to ensure clean removal of border pixels
188+ lv_obj_invalidate (lv_scr_act ());
189189 } else {
190- lv_obj_clear_flag (critical_border, LV_OBJ_FLAG_HIDDEN);
191- // Invalidate the border area to ensure clean redraw
192- lv_obj_invalidate (critical_border);
190+ lv_obj_set_style_border_opa (critical_border, LV_OPA_100, LV_PART_MAIN);
193191 lv_timer_set_period (timer, 300 ); // On duration
194192
195193 // Trigger vibration pulse in sync with border "on"
196194 if (ENABLE_VIBE) {
197195 pulseVibration (300 , 200 ); // 300ms pulse, intensity 200
198196 }
197+ // Invalidate the border area when showing
198+ lv_obj_invalidate (critical_border);
199199 }
200200 // Force immediate refresh to minimize tearing
201201 lv_refr_now (lv_disp_get_default ());
@@ -206,7 +206,7 @@ void startCriticalBorderFlash() {
206206 if (xSemaphoreTake (lvglMutex, pdMS_TO_TICKS (50 )) == pdTRUE) {
207207 if (critical_border != NULL && !isFlashingCriticalBorder) {
208208 isFlashingCriticalBorder = true ;
209- lv_obj_clear_flag (critical_border, LV_OBJ_FLAG_HIDDEN ); // Start visible
209+ lv_obj_set_style_border_opa (critical_border, LV_OPA_100, LV_PART_MAIN ); // Start visible
210210 critical_border_flash_timer = lv_timer_create (critical_border_flash_timer_cb, 300 , NULL );
211211 }
212212 xSemaphoreGive (lvglMutex);
@@ -220,7 +220,9 @@ void stopCriticalBorderFlash() {
220220 critical_border_flash_timer = NULL ;
221221 }
222222 if (critical_border != NULL ) {
223- lv_obj_add_flag (critical_border, LV_OBJ_FLAG_HIDDEN);
223+ lv_obj_set_style_border_opa (critical_border, LV_OPA_0, LV_PART_MAIN);
224+ // Invalidate entire screen to ensure clean removal
225+ lv_obj_invalidate (lv_scr_act ());
224226 }
225227 isFlashingCriticalBorder = false ;
226228 xSemaphoreGive (lvglMutex);
@@ -235,7 +237,7 @@ bool isCriticalBorderFlashing() {
235237void startCriticalBorderFlashDirect () {
236238 if (critical_border != NULL && !isFlashingCriticalBorder) {
237239 isFlashingCriticalBorder = true ;
238- lv_obj_clear_flag (critical_border, LV_OBJ_FLAG_HIDDEN ); // Start visible
240+ lv_obj_set_style_border_opa (critical_border, LV_OPA_100, LV_PART_MAIN ); // Start visible
239241 lv_obj_invalidate (critical_border); // Ensure clean initial draw
240242 critical_border_flash_timer = lv_timer_create (critical_border_flash_timer_cb, 300 , NULL );
241243 // Force immediate refresh for clean start
@@ -249,8 +251,8 @@ void stopCriticalBorderFlashDirect() {
249251 critical_border_flash_timer = NULL ;
250252 }
251253 if (critical_border != NULL ) {
252- lv_obj_add_flag (critical_border, LV_OBJ_FLAG_HIDDEN );
253- lv_obj_invalidate (critical_border) ; // Ensure clean removal
254+ lv_obj_set_style_border_opa (critical_border, LV_OPA_0, LV_PART_MAIN );
255+ lv_obj_invalidate (lv_scr_act ()) ; // Ensure clean removal of border
254256 // Force immediate refresh for clean stop
255257 lv_refr_now (lv_disp_get_default ());
256258 }
0 commit comments