How improve responsiveness on button press with many actions?

Description

Hi! I’m setting up a wifi connect screen. The starting state has all items hidden-flag set true except a “scan” button. The callback for the scan button, in essence, should:

  1. Unflag hidden from a spinner widget
  2. Starts an async WiFi.scanNetworks call
    2a) on finding networks, unhides a roller widget and a select button, and hides the spinner
    2b) on finding no networks, hides the spinner and displays a no networks found message

And so on through the wifi connection process - brings up a keyboard when a network is selected, hides the select button, shows a connect and cancel button that go on to revert or progress the process.

However, upon pressing the initial scan button, the UI appears to lock until all of the work inside the callback is finished. The button clearly renders in the “pressed” state until the full network scan is over, during which times there should have been a few ui updates.

A simple way to reproduce is below.

What MCU/Processor/Board and compiler are you using?

lilygo t-display s3 (esp32s3) using platformio

What LVGL version are you using?

8.3.11

What have you tried so far?

I am unsure of the correct pattern to achieve the level of responsiveness I’m looking for. I have considering registering a bunch of tasks and having the different buttons trigger tasks and subtasks but that would be incredibly awkward.

Code to reproduce

Here is a much simplified example

void scanWifiEventHandler(lv_event_t * e) {
    Serial.println("wifi scan start");
    // I expect this to happen before the delay begins
    lv_obj_clear_flag(ui_wifiSpinner, LV_OBJ_FLAG_HIDDEN);
    // Nothing happens until the delay ends
    delay(1000);
}

Here is a more comprehensive look at the actual code for anyone interested:

void scanWifiEventHandler(lv_event_t * e) {

    Serial.println("Wifi scan wating on semaphore");
    if ( xSemaphoreTake( xWiFiLock, portMAX_DELAY ) == pdTRUE ) {
        Serial.println("wifi scan start");

        int16_t wifi_scan_status;

        ui_set_no_networks();
        ui_set_on_visibility(ui_wifiSpinner);

        // async scan to not block watchdog
        WiFi.disconnect();
        delay(250);
        Serial.println("wifi disconnected");

        WiFi.scanNetworks(true);

        // wait for wifi scan result
        Serial.println("waiting for result");

        while(1) {
            delay(250);
            wifi_scan_status = WiFi.scanComplete();

            if (wifi_scan_status == WIFI_SCAN_FAILED) {
                Serial.println("WIFI SCAN FAILED!");
                break;
            } else if (wifi_scan_status == WIFI_SCAN_RUNNING){
                Serial.println("Continuing to search");
                continue;
            } else {
                Serial.println("status check:");
                Serial.println(wifi_scan_status);
                break;
            }
        }
        Serial.println("wifi scan result count:");
        Serial.println(wifi_scan_status);

        if (wifi_scan_status > 0) {
            ui_set_found_networks();
            ui_roller_show_results(wifi_scan_status);
            ui_set_off_visibility(ui_wifiSpinner);
        }
    };
    xSemaphoreGive( xWiFiLock );
}

as far as I understand ui locks due to use delay() inside event handler. so just move scan procedure into separate task suspended by default and resume task when button pressed. in main loop check wifi scan status and control widgets of ui depending this state.