diff --git a/libraries/networking/src/ResourceCache.cpp b/libraries/networking/src/ResourceCache.cpp index 3e7e8dd345..aa42f94e8b 100644 --- a/libraries/networking/src/ResourceCache.cpp +++ b/libraries/networking/src/ResourceCache.cpp @@ -121,7 +121,17 @@ QSharedPointer ResourceCacheSharedItems::getHighestPendingRequest() { ScriptableResource::ScriptableResource(const QUrl& url) : QObject(nullptr), - _url(url) {} + _url(url) { + + // Expose enum State to JS/QML via properties + QObject* state = new QObject(this); + state->setObjectName("ResourceState"); + setProperty("State", QVariant::fromValue(state)); + auto metaEnum = QMetaEnum::fromType(); + for (int i = 0; i < metaEnum.keyCount(); ++i) { + state->setProperty(metaEnum.key(i), metaEnum.value(i)); + } +} void ScriptableResource::release() { disconnectHelper(); @@ -135,22 +145,30 @@ void ScriptableResource::updateMemoryCost(const QObject* engine) { } } +void ScriptableResource::loadingChanged() { + emit stateChanged(LOADING); +} + +void ScriptableResource::loadedChanged() { + emit stateChanged(LOADED); +} + void ScriptableResource::finished(bool success) { disconnectHelper(); - _isLoaded = true; - _isFailed = !success; - - if (_isFailed) { - emit failedChanged(_isFailed); - } - emit loadedChanged(_isLoaded); + emit stateChanged(success ? FINISHED : FAILED); } void ScriptableResource::disconnectHelper() { if (_progressConnection) { disconnect(_progressConnection); } + if (_loadingConnection) { + disconnect(_loadingConnection); + } + if (_loadedConnection) { + disconnect(_loadedConnection); + } if (_finishedConnection) { disconnect(_finishedConnection); } @@ -180,6 +198,12 @@ ScriptableResource* ResourceCache::prefetch(const QUrl& url, void* extra) { result->_progressConnection = connect( resource.data(), &Resource::onProgress, result, &ScriptableResource::progressChanged); + result->_loadingConnection = connect( + resource.data(), &Resource::loading, + result, &ScriptableResource::loadingChanged); + result->_loadedConnection = connect( + resource.data(), &Resource::loaded, + result, &ScriptableResource::loadedChanged); result->_finishedConnection = connect( resource.data(), &Resource::finished, result, &ScriptableResource::finished); @@ -644,6 +668,7 @@ void Resource::makeRequest() { } qCDebug(networking).noquote() << "Starting request for:" << _url.toDisplayString(); + emit loading(); connect(_request, &ResourceRequest::progress, this, &Resource::onProgress); connect(this, &Resource::onProgress, this, &Resource::handleDownloadProgress); diff --git a/libraries/networking/src/ResourceCache.h b/libraries/networking/src/ResourceCache.h index 7d9e0f65fd..904da4f097 100644 --- a/libraries/networking/src/ResourceCache.h +++ b/libraries/networking/src/ResourceCache.h @@ -82,28 +82,36 @@ private: class ScriptableResource : public QObject { Q_OBJECT Q_PROPERTY(QUrl url READ getUrl) - Q_PROPERTY(bool loaded READ isLoaded NOTIFY loadedChanged) - Q_PROPERTY(bool failed READ isFailed NOTIFY failedChanged) + Q_PROPERTY(int state READ getState NOTIFY stateChanged) public: + enum State { + QUEUED, + LOADING, + LOADED, + FINISHED, + FAILED, + }; + Q_ENUM(State) + ScriptableResource(const QUrl& url); virtual ~ScriptableResource() = default; Q_INVOKABLE void release(); const QUrl& getUrl() const { return _url; } - bool isLoaded() const { return _isLoaded; } - bool isFailed() const { return _isFailed; } + int getState() const { return (int)_state; } - // Connects to a SLOT(updateMemoryCost(qint64) on the given engine + // Connects to a SLOT(updateMemoryCost(qint64)) on the given engine void updateMemoryCost(const QObject* engine); signals: void progressChanged(uint64_t bytesReceived, uint64_t bytesTotal); - void loadedChanged(bool loaded); // analogous to &Resource::finished - void failedChanged(bool failed); + void stateChanged(int state); private slots: + void loadingChanged(); + void loadedChanged(); void finished(bool success); private: @@ -115,11 +123,12 @@ private: QSharedPointer _resource; QMetaObject::Connection _progressConnection; + QMetaObject::Connection _loadingConnection; + QMetaObject::Connection _loadedConnection; QMetaObject::Connection _finishedConnection; QUrl _url; - bool _isLoaded{ false }; - bool _isFailed{ false }; + State _state{ QUEUED }; }; Q_DECLARE_METATYPE(ScriptableResource*); @@ -287,6 +296,9 @@ public: const QUrl& getURL() const { return _url; } signals: + /// Fired when the resource begins downloading. + void loading(); + /// Fired when the resource has been downloaded. /// This can be used instead of downloadFinished to access data before it is processed. void loaded(const QByteArray request); diff --git a/scripts/developer/tests/scriptableResource/lib.js b/scripts/developer/tests/scriptableResource/lib.js index ed3d746061..21e2e64cae 100644 --- a/scripts/developer/tests/scriptableResource/lib.js +++ b/scripts/developer/tests/scriptableResource/lib.js @@ -22,11 +22,12 @@ function getFrame(callback) { if (model.loaded) { makeFrame(true); } else { - model.loadedChanged.connect(makeFrame); + model.stateChanged.connect(makeFrame); } - function makeFrame(success) { - if (!success) { throw "Failed to load frame"; } + function makeFrame(state) { + if (state == 4) { throw "Failed to load frame"; } + if (state != 3) { return; } var pictureFrameProperties = { name: 'scriptableResourceTest Picture Frame', @@ -68,9 +69,11 @@ function prefetch(callback) { frames.push(texture); if (!texture.loaded) { numLoading++; - texture.loadedChanged.connect(function() { - --numLoading; - if (!numLoading) { callback(frames); } + texture.stateChanged.connect(function(state) { + if (state == 3 || state == 4) { + --numLoading; + if (!numLoading) { callback(frames); } + } }); } }