diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 509e7625ae9146eb1ab484c74883da3f22538657..ccd0a95af41a2d7f876262f730d50b0422a066a7 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -1,6 +1,6 @@ <?xml version="1.0"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.qt.qtdesignviewer" - android:installLocation="auto" android:versionCode="25" android:versionName="1.2"> + android:installLocation="auto" android:versionCode="26" android:versionName="1.2"> <!-- %%INSERT_PERMISSIONS --> <!-- %%INSERT_FEATURES --> <supports-screens android:anyDensity="true" android:largeScreens="true" diff --git a/src/backend.cpp b/src/backend.cpp index 78ce526f42ad8ec69bf85b22ba5e5d241468322a..e74167329361c795e4fdcf4a22660488ec9a00fc 100644 --- a/src/backend.cpp +++ b/src/backend.cpp @@ -336,16 +336,18 @@ void Backend::runDemoProject(const QString &projectName) // sample project info // [{"lastUpdate":1701947766739.9812,"name":"ClusterTutorial.qmlrc"}] - const QJsonArray projectList = m_serviceConnector.fetchUserDemoList(); + const std::optional<QJsonArray> projectList = m_serviceConnector.fetchDemoList(); - if (projectList.isEmpty()) { - qCritical("Please check your internet connection and try again"); + if (projectList == std::nullopt) { + qCritical() + << "Could not fetch demo project list. Please check your internet connection and " + "try again."; emit popupClose(); return; } QJsonObject projectInfo; - for (auto project : projectList) { + for (auto project : projectList.value()) { if (projectName == project.toObject().value("name").toString().remove(".qmlrc")) { projectInfo = project.toObject(); break; @@ -357,13 +359,18 @@ void Backend::runDemoProject(const QString &projectName) if (!cached) { updatePopup("Downloading demo project...", false); - const QString url = "https://designviewer.qt.io/qmlprojects/demos/" + projectName - + ".qmlrc"; - QByteArray project = m_serviceConnector.fetchProject(url); - qDebug() << "Demo project is not cached. Trying to download from " << url << " ..."; + const std::optional<QByteArray> project = m_serviceConnector.fetchDemo(projectName + + ".qmlrc"); + + if (project == std::nullopt) { + qCritical() << "Could not download demo project. Please check the logs for more " + "information."; + emit popupClose(); + return; + } updatePopup("Caching demo project..."); - if (!m_projectManager->cacheDemoProject(project, projectInfo)) { + if (!m_projectManager->cacheDemoProject(project.value(), projectInfo)) { qCritical() << "Could not cache demo project. Please check the logs for more information."; emit popupClose(); @@ -405,10 +412,11 @@ void Backend::runUserProject(const QString &projectName) const QString userHash = Backend::userHash(); qDebug("Checking if project is cached. Getting list of available projects..."); - const QJsonArray projectList = m_serviceConnector.fetchUserProjectList(userHash); + const std::optional<QJsonArray> projectList = m_serviceConnector.fetchUserProjectList(userHash); - if (projectList.isEmpty()) { - qCritical("Please check your internet connection and try again"); + if (projectList == std::nullopt) { + qCritical() << "Could not fetch up-to-date project information. Please check your internet " + "connection and try again."; emit popupClose(); return; } @@ -416,7 +424,7 @@ void Backend::runUserProject(const QString &projectName) QString projectLastModified; QString projectId; QJsonObject projectInfo; - for (auto project : projectList) { + for (auto project : projectList.value()) { if (projectName == project.toObject().value("appName").toString()) { projectInfo = project.toObject(); break; @@ -428,10 +436,18 @@ void Backend::runUserProject(const QString &projectName) if (!projectCached) { qDebug("Project is not cached. Downloading..."); updatePopup("Project is not cached. Downloading...", false); - QByteArray projectData = m_serviceConnector.fetchUserProject(userHash, projectName); + const std::optional<QByteArray> projectData + = m_serviceConnector.fetchUserProject(userHash, projectName); + + if (projectData == std::nullopt) { + qCritical() + << "Could not download project. Please check the logs for more information."; + emit popupClose(); + return; + } updatePopup("Caching user project..."); - if (!m_projectManager->cacheProject(projectData, projectInfo)) { + if (!m_projectManager->cacheProject(projectData.value(), projectInfo)) { qCritical() << "Could not cache project. Please check the logs for more information."; emit popupClose(); return; @@ -455,14 +471,16 @@ void Backend::runOnlineProject(const QString &url) initializeProjectManager(); emit popupOpen(); updatePopup("Downloading...", false); - QByteArray projectData = m_serviceConnector.fetchProject(url); - if (projectData.isEmpty()) { + const std::optional<QByteArray> projectData = m_serviceConnector.fetchProject(url); + + if (projectData == std::nullopt) { qCritical() << "Could not download project. Please check the logs for more information."; + emit popupClose(); return; } updatePopup("Unpacking project..."); - QString projectPath = m_projectManager->unpackProject(projectData); + QString projectPath = m_projectManager->unpackProject(projectData.value()); updatePopup("Running project..."); if (!m_projectManager->runProject(projectPath)) @@ -484,16 +502,16 @@ void Backend::updateUserProjectList() } qDebug() << "Fetching available project list for user:" << userHash; - QJsonArray projectList = m_serviceConnector.fetchUserProjectList(userHash); + const std::optional<QJsonArray> projectList = m_serviceConnector.fetchUserProjectList(userHash); - if (projectList == m_projectList) { + if (projectList == std::nullopt) { + qWarning( + "Could not fetch project list. Please check your internet connection and try again."); + } else if (projectList.value() == m_projectList) { qDebug("No new projects are available"); - } else if (projectList.isEmpty()) { - qWarning("Could not fetch project list. Either there are no projects or there is a " - "network issue"); } else { qDebug("List of available projects fetched:"); - for (const auto &project : projectList) { + for (const auto &project : projectList.value()) { const QString projectName{project.toObject().value("appName").toString()}; qDebug() << "--" << projectName; } @@ -502,7 +520,7 @@ void Backend::updateUserProjectList() // we need to set m_projectList even if it is empty // because this triggers the onModelChanged function in the QML // in order to update the UI - m_projectList = projectList; + m_projectList = projectList.value(); emit projectListChanged(); } diff --git a/src/projectManager.cpp b/src/projectManager.cpp index b60006e7c3d305f2113d3503d47393404e671626..f7cf843a1fc8ef84fe74cae3c2e7f314a7c66c5f 100644 --- a/src/projectManager.cpp +++ b/src/projectManager.cpp @@ -81,7 +81,7 @@ void ProjectManager::cleanupResources() << " Size: " << m_projectData.size() << " bytes."; data = reinterpret_cast<const uchar *>(m_projectData.data()); if (!QResource::unregisterResource(data, m_projectPath)) { - qCritical("Cannot unregister the previous resource data."); + qCritical() << "Cannot unregister the previous resource data."; } } } @@ -124,8 +124,8 @@ QString ProjectManager::unpackProject(const QByteArray &project, bool extractZip } if (!QResource::registerResource(data, resourcePath)) { - qCritical("Can not load the resource data."); - return ""; + qCritical() << "Can not load the resource data."; + return {}; } projectPath = ":" + resourcePath; diff --git a/src/serviceConnector.cpp b/src/serviceConnector.cpp index 01ec60a0db378509a0939a74a3d088687012f80e..d8ced5d8d0d32dbe737af9ffe47fa13fed67ff9d 100644 --- a/src/serviceConnector.cpp +++ b/src/serviceConnector.cpp @@ -31,7 +31,7 @@ #include <QJsonDocument> #include <QJsonObject> -QByteArray ServiceConnector::fetchResource(const QString &url, const bool quite) +std::optional<QByteArray> ServiceConnector::fetchResource(const QString &url) { qDebug() << "Fetching resource from" << url; @@ -42,10 +42,7 @@ QByteArray ServiceConnector::fetchResource(const QString &url, const bool quite) &QNetworkReply::sslErrors, this, [&](const QList<QSslError> &errors) { - if (!quite) - qCritical() << errors.first().errorString(); - else - qWarning() << errors.first().errorString(); + qWarning() << errors.first().errorString(); }); QEventLoop loop; @@ -63,47 +60,42 @@ QByteArray ServiceConnector::fetchResource(const QString &url, const bool quite) loop.exec(); if (reply->error() != QNetworkReply::NoError) { - if (!quite) - qCritical() << reply->errorString(); - else - qWarning() << reply->errorString(); - } else { - qDebug() << "Resource fetched successfully"; + qWarning() << reply->errorString(); + return {}; } + qDebug() << "Resource fetched successfully"; return reply->readAll(); } -QByteArray ServiceConnector::fetchProject(const QString &url) +std::optional<QByteArray> ServiceConnector::fetchProject(const QString &url) { QString projectUrl = url; - if (projectUrl.startsWith("https://designviewer.qt.io/#")) - { + if (projectUrl.startsWith(m_serviceUrl + "/#")) { projectUrl = projectUrl.split("#").at(1); - projectUrl.prepend("https://designviewer.qt.io/qmlprojects/"); + projectUrl.prepend(m_serviceUrl + "/qmlprojects/"); } return fetchResource(projectUrl); } -QByteArray ServiceConnector::fetchUserProject(const QString &userHash, const QString &projectName) +std::optional<QByteArray> ServiceConnector::fetchUserProject(const QString &userHash, + const QString &projectName) { - const QString projectUrl = "https://designviewer.qt.io/qmlprojects/" + userHash + "/" - + projectName + ".qmlrc"; + const QString projectUrl = m_serviceUrl + "/qmlprojects/" + userHash + "/" + projectName + + ".qmlrc"; + return fetchResource(projectUrl); } -QJsonArray ServiceConnector::fetchUserProjectList(const QString &userHash) +std::optional<QJsonArray> ServiceConnector::fetchUserProjectList(const QString &userHash) { - auto reply = fetchResource("https://designviewer.qt.io/api/v1/qmlrc/list/" + userHash - + "?key=818815", - true); + auto reply = fetchResource(m_serviceUrl + "/api/v1/qmlrc/list/" + userHash + "?key=818815"); - if (reply.size() == 0) { - return QJsonArray(); - } + if (!reply) + return {}; - QJsonArray projectList = QJsonDocument::fromJson(reply) + QJsonArray projectList = QJsonDocument::fromJson(reply.value()) .object() .value("data") .toObject() @@ -113,12 +105,16 @@ QJsonArray ServiceConnector::fetchUserProjectList(const QString &userHash) return projectList; } -QJsonArray ServiceConnector::fetchUserDemoList() +std::optional<QJsonArray> ServiceConnector::fetchDemoList() { - auto reply = fetchResource("https://designviewer.qt.io/api/v1/demos"); - if (reply.size() == 0) { - return QJsonArray(); - } + auto reply = fetchResource(m_serviceUrl + "/api/v1/demos"); + if (!reply) + return {}; - return QJsonDocument::fromJson(reply).array(); + return QJsonDocument::fromJson(reply.value()).array(); +} + +std::optional<QByteArray> ServiceConnector::fetchDemo(const QString &demoName) +{ + return fetchResource(m_serviceUrl + "/qmlprojects/demos/" + demoName + ".qmlrc"); } diff --git a/src/serviceConnector.h b/src/serviceConnector.h index ad0c4d9b5beafb7915fc15622195a44c94fd0cb4..3ee827deeb921ee5a7fb51f4def1f49579762985 100644 --- a/src/serviceConnector.h +++ b/src/serviceConnector.h @@ -33,14 +33,17 @@ class ServiceConnector : public QObject { Q_OBJECT public: - QByteArray fetchProject(const QString &url); - QByteArray fetchUserProject(const QString &userHash, const QString &projectName); - QJsonArray fetchUserProjectList(const QString &userHash); - QJsonArray fetchUserDemoList(); + std::optional<QByteArray> fetchProject(const QString &url); + std::optional<QByteArray> fetchUserProject(const QString &userHash, const QString &projectName); + std::optional<QJsonArray> fetchUserProjectList(const QString &userHash); + std::optional<QJsonArray> fetchDemoList(); + std::optional<QByteArray> fetchDemo(const QString &demoName); private: QNetworkAccessManager m_manager; - QByteArray fetchResource(const QString &url, const bool quite = false); + std::optional<QByteArray> fetchResource(const QString &url); + + const QString m_serviceUrl = "https://designviewer.qt.io"; signals: void downloadProgress(float percentage);