danvratil / qcoro

C++ Coroutines for Qt
https://qcoro.dvratil.cz
MIT License
326 stars 53 forks source link

Qt Design Studio : Mocking QCoro::QmlTask in Javascript or QML #203

Closed jacquetc closed 8 months ago

jacquetc commented 8 months ago

Hello,

Very nice library ! I liked your idea so much than I'm integrating it in my own framework Qleany.

The workflow pushed by Qt is to use Qt Design Studio to create the GUI in QML. To do that, we need to mock the backend API in Javascript. It's where I'm stuck with QCoro::QmlTask. In the framework example, for this C++ file here, I mocked it here.

As you can see, I used Promise in JS to get a ".then()", but I'm stuck with reproducing the ".await().value". Do you have any idea to completely mock QmlTask ?

Regards, Cyril

jacquetc commented 8 months ago

Sorry, I was a bit tired. The solution wasn't hard.

For those looking for the answer, I did the following:

Function to be mocked in a C++ QML Element:

    Q_INVOKABLE QCoro::QmlTask create(const CreateCarDTO &dto)
    {
        return s_controllerInstance->create(dto);
    }

Mocked QCoro::QmlTask

// QCoroQmlTask.qml file:
import QtQuick

QtObject {

     property QtObject priv: QtObject {
         property QtObject awaitObject: QtObject{
            property var value
         }

        property int delay: 50
        property var signalFn: function(){}

     }

    function setValue(value){
        priv.awaitObject.value = value
    }

    function setDelay(delay){
        priv.delay = delay
    }

    function setSignalFn(fn){
        priv.signalFn = fn
    }

    function await(){
        return awaitObject
    }

    function then(fn){
        var promise = new Promise((resolve, reject) => {
                                       var timer = Qt.createQmlObject('import QtQuick 2.0; Timer {}', Qt.application);
                                       timer.interval = 50; // delay
                                       timer.repeat = false;
                                       timer.triggered.connect(() => {
                                                                   fn(priv.awaitObject.value)
                                                                   priv.signalFn()
                                                                   resolve();
                                                                   timer.destroy(); // Clean up the timer
                                                               });
                                       timer.start();
                                   })

    }
}

Mocked function:

    function create(dto) {
        // create random id
        var newId = Math.floor(Math.random() * 1000000);
        dto["id"] = newId;

        var component = Qt.createComponent("CoroQmlTask.qml");
        if (component.status === Component.Ready) {
            var task = component.createObject(controller);
            task.setValue(dto);
            task.setSignalFn(function(){EventDispatcher.car().created(dto)})
        }

        return task
    }
danvratil commented 8 months ago

I was going to suggest something similar...

I'm closing the issue, since it's resolved for you :)

jacquetc commented 8 months ago

Thank you !