diff --git a/3rdparty/qtquickdesigner-components b/3rdparty/qtquickdesigner-components index de28bdbdfb1a9393ca87febafb319125e5578d11..59721758afe9d7034ca76f1a19c3c5c97610ceaa 160000 --- a/3rdparty/qtquickdesigner-components +++ b/3rdparty/qtquickdesigner-components @@ -1 +1 @@ -Subproject commit de28bdbdfb1a9393ca87febafb319125e5578d11 +Subproject commit 59721758afe9d7034ca76f1a19c3c5c97610ceaa diff --git a/CMakeLists.txt b/CMakeLists.txt index 9c2f4ad05e4d7c34fd07cdc1f411032e2c9bfe77..e0277147598d42872b814222d9ec98ee9e07ae0c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,13 +13,13 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) find_package( QT NAMES Qt6 - COMPONENTS Core + COMPONENTS Core Widgets Quick Gui Qml Multimedia MultimediaWidgets Concurrent REQUIRED ) find_package( Qt6 - COMPONENTS Core Widgets Quick Gui Qml Multimedia MultimediaWidgets + COMPONENTS Core Widgets Quick Gui Qml Multimedia MultimediaWidgets Concurrent REQUIRED ) @@ -44,9 +44,11 @@ qt_add_executable(${PROJECT_NAME} ) target_link_libraries(${PROJECT_NAME} PRIVATE - Qt::Core Qt::Widgets - Qt::Quick Qt::Gui - Qt::Qml Qt::GuiPrivate Qt::Multimedia Qt::MultimediaWidgets + Qt6::Core Qt6::Widgets + Qt6::Quick Qt6::Gui + Qt6::Qml Qt6::GuiPrivate + Qt6::Multimedia Qt6::MultimediaWidgets + Qt6::Concurrent ZXing::ZXing ) diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 0bfd19b182210842e681b5775ac7f0239304bd87..1251571bca57fa8539509a40203a3d3974986829 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="23" android:versionName="1.2"> + android:installLocation="auto" android:versionCode="24" 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 800d3b49211e09c8808f4f4db0a2c8b47a06dedf..639f3ea2a808d079f791381e5c32c6828407689f 100644 --- a/src/backend.cpp +++ b/src/backend.cpp @@ -28,13 +28,17 @@ #include <QCameraDevice> #include <QDesktopServices> +#include <QElapsedTimer> #include <QFileInfo> #include <QJsonArray> #include <QJsonObject> #include <QMediaDevices> +#include <QMessageBox> +#include <QPermission> #include <QSettings> #include <QSslSocket> #include <QVideoSink> +#include <QtConcurrent> #include "../3rdparty/zxing-cpp/example/ZXingQtReader.h" @@ -52,6 +56,11 @@ Backend::Backend(QObject *parent) &Backend::initDesignStudioConnector, Qt::DirectConnection); m_dsConnectorThread.start(); + + connect(&m_serviceConnector, + &ServiceConnector::downloadProgress, + this, + &Backend::downloadProgress); } void Backend::initialize() @@ -76,48 +85,126 @@ void Backend::initialize() + QVariant(QSslSocket::supportsSsl()).toString(); emit buildInfoChanged(buildInfo); - QSettings settings; - m_userHash = settings.value("user/hash").toString(); - if (m_userHash.isEmpty()) + if (userHash().isEmpty()) qDebug("User Hash is not registered. Scan QR code to register."); else { - qDebug() << "User Hash: " << m_userHash; + qDebug() << "User Hash: " << userHash(); updateUserProjectList(); } // Check if updateInBackground is enabled - updateInBackground(settings.value("system/updateInBackground").toBool()); + enableBackgroundUpdate(updateInBackground()); qDebug() << "Initialization complete"; } -void Backend::updateInBackground(const bool &enabled) +void Backend::enableBackgroundUpdate(const bool &enabled) { - QSettings().setValue("system/updateInBackground", enabled); if (enabled) { - qDebug() << "Update in background is enabled"; m_backgroundTimer.setInterval(1000 * 10); + connect(&m_backgroundTimer, &QTimer::timeout, this, [&] { qDebug() << "Checking for updates in background"; - if (m_userHash.isEmpty()) + + const QString userHash = Backend::userHash(); + if (userHash.isEmpty()) return; - m_serviceConnector.reset(new ServiceConnector); - QJsonArray projectList = m_serviceConnector->fetchUserProjectList(m_userHash); - if (projectList.isEmpty()) + QJsonArray projectList = m_serviceConnector.fetchUserProjectList(userHash); + if (projectList.isEmpty()) { + qWarning() << "Could not fetch project list. Please check your internet " + "connection and try again"; return; + } qDebug() << "New projects available. Updating project list"; updateUserProjectList(); }); + m_backgroundTimer.start(); } else { - qDebug() << "Update in background is disabled"; m_backgroundTimer.stop(); } } +void Backend::setUpdateInBackground(const bool &enabled) +{ + QSettings().setValue("system/updateInBackground", enabled); + if (enabled) { + qDebug() << "Update in background is enabled"; + } else { + qDebug() << "Update in background is disabled"; + } + enableBackgroundUpdate(enabled); +} + +void Backend::setAutoScaleProject(const bool &enabled) +{ + QSettings().setValue("system/autoScaleProject", enabled); + if (enabled) { + qDebug() << "Auto scale project is enabled"; + } else { + qDebug() << "Auto scale project is disabled"; + } +} + +void Backend::setUserHash(const QString &userHash) +{ + QSettings().setValue("user/hash", userHash); + updateUserProjectList(); +} + +bool Backend::updateInBackground() +{ + return QSettings().value("system/updateInBackground", false).toBool(); +} + +bool Backend::autoScaleProject() +{ + return QSettings().value("system/autoScaleProject", true).toBool(); +} + +QString Backend::userHash() +{ + return QSettings().value("user/hash").toString(); +} + +void Backend::updatePopup(const QString &text, bool indeterminate) +{ + emit popupTextChanged(text); + emit popupProgressIndeterminateChanged(indeterminate); + QEventLoop().processEvents(QEventLoop::AllEvents, 1000); +} + void Backend::scanQrCode() { + // request permissions + QCameraPermission permission; + QCoreApplication &app = *QCoreApplication::instance(); + switch (app.checkPermission(permission)) { + case Qt::PermissionStatus::Granted: + openCamera(); + break; + case Qt::PermissionStatus::Undetermined: + case Qt::PermissionStatus::Denied: + app.requestPermission(permission, [this](const QPermission &permission) { + if (permission.status() == Qt::PermissionStatus::Denied) { + QMessageBox msgBox{QMessageBox::Critical, + "Critical:", + "Camera permission denied", + QMessageBox::Ok}; + msgBox.exec(); + return; + } + + openCamera(); + }); + break; + } +} + +void Backend::openCamera() +{ + // start camera m_captureSession.reset(new QMediaCaptureSession(this)); m_captureSession->setCamera(new QCamera(this)); m_captureSession->setVideoOutput(new CustomVideoWidget); @@ -132,22 +219,60 @@ void Backend::scanQrCode() this, [&](const QVideoFrame &frame) { static int i = 0; - if (i++ < 30) { + static QAtomicInt running = 0; + + if (i++ < 20 || running > 0) { return; } i = 0; - auto results = ReadBarcodes(frame.toImage()); - for (auto &result : results) { + QtConcurrent::run([=] { + // lock the thread so that only one barcode can be read at a time + running++; + + QElapsedTimer timer; + timer.start(); + QList<Result> results = ReadBarcodes(frame.toImage()); + qDebug() << "Barcode detection took" << timer.elapsed() << "ms"; + + // release the lock so that another barcode can be read + running--; + return results; + }).then([=](const QList<Result> &results) { + if (results.isEmpty() || !m_captureSession) + return; + + qDebug() << "Stopping camera"; + qobject_cast<CustomVideoWidget *>(m_captureSession->videoOutput())->close(); + qDebug() << "Camera stopped"; + + Result result = results.first(); + qDebug() << "Text: " << result.text(); qDebug() << "Format: " << result.format(); qDebug() << "Content:" << result.contentType(); - parseDesignViewerUrl(result.text()); - qobject_cast<CustomVideoWidget *>(m_captureSession->videoOutput())->close(); - } + + // we have to use invokeMethod because we are in a different thread + // then where the serviceConnector is created + QMetaObject::invokeMethod(this, + "parseDesignViewerUrl", + Qt::QueuedConnection, + Q_ARG(QUrl, result.text())); + }); }); + // stop camera when app is not active. + // i.e. when the user switches to another app or the screen is locked + QGuiApplication *app(qobject_cast<QGuiApplication *>(QCoreApplication::instance())); + connect(app, &QGuiApplication::applicationStateChanged, this, [&](Qt::ApplicationState state) { + if (state != Qt::ApplicationState::ApplicationActive && m_captureSession) { + qDebug() << "Application is not active. Stopping camera"; + qobject_cast<CustomVideoWidget *>(m_captureSession->videoOutput())->close(); + } + }); + + // stop camera when video widget is closed connect(videoWidget, &CustomVideoWidget::closed, this, [&] { qDebug() << "Video widget closed. Clearing capture session"; m_captureSession->camera()->stop(); @@ -156,52 +281,21 @@ void Backend::scanQrCode() m_captureSession.clear(); }); + videoWidget->setWindowFlags(Qt::Window | Qt::WindowStaysOnTopHint); videoWidget->show(); m_captureSession->camera()->start(); } -void Backend::cacheDemoProjects(const bool &enabled) -{ - QSettings().setValue("system/cacheDemoProjects", enabled); - if (enabled) { - qDebug() << "Caching demo projects is enabled"; - } else { - qDebug() << "Caching demo projects is disabled"; - } -} -void Backend::cacheUserProjects(const bool &enabled) -{ - QSettings().setValue("system/cacheUserProjects", enabled); - if (enabled) { - qDebug() << "Caching user projects is enabled"; - } else { - qDebug() << "Caching user projects is disabled"; - } -} - -void Backend::updatePopup(const QString &text, bool indeterminate) -{ - emit popupTextChanged(text); - emit popupProgressIndeterminateChanged(indeterminate); - QEventLoop().processEvents(QEventLoop::AllEvents, 1000); -} - void Backend::initializeProjectManager() { if (m_projectManager) return; - m_projectManager.reset(new ProjectManager); + m_projectManager.reset(new ProjectManager(autoScaleProject())); connect(m_projectManager.data(), &ProjectManager::closingProject, this, [&] { emit popupClose(); m_projectManager.reset(); }); - - m_serviceConnector.reset(new ServiceConnector); - connect(m_serviceConnector.data(), - &ServiceConnector::downloadProgress, - this, - &Backend::downloadProgress); } void Backend::initDesignStudioConnector() @@ -255,7 +349,14 @@ void Backend::runDemoProject(const QString &projectName) // sample project info // [{"lastUpdate":1701947766739.9812,"name":"ClusterTutorial.qmlrc"}] - const QJsonArray projectList = m_serviceConnector->fetchUserDemoList(); + const QJsonArray projectList = m_serviceConnector.fetchUserDemoList(); + + if (projectList.isEmpty()) { + qCritical("Please check your internet connection and try again"); + emit popupClose(); + return; + } + QJsonObject projectInfo; for (auto project : projectList) { if (projectName == project.toObject().value("name").toString().remove(".qmlrc")) { @@ -271,7 +372,7 @@ void Backend::runDemoProject(const QString &projectName) const QString url = "https://designviewer.qt.io/qmlprojects/demos/" + projectName + ".qmlrc"; - QByteArray project = m_serviceConnector->fetchProject(url); + QByteArray project = m_serviceConnector.fetchProject(url); qDebug() << "Demo project is not cached. Trying to download from " << url << " ..."; updatePopup("Caching demo project..."); @@ -314,8 +415,16 @@ void Backend::runUserProject(const QString &projectName) qDebug() << "Running user project:" << projectName; + const QString userHash = Backend::userHash(); + qDebug("Checking if project is cached. Getting list of available projects..."); - const QJsonArray projectList = m_serviceConnector->fetchUserProjectList(m_userHash); + const QJsonArray projectList = m_serviceConnector.fetchUserProjectList(userHash); + + if (projectList.isEmpty()) { + qCritical("Please check your internet connection and try again"); + emit popupClose(); + return; + } QString projectLastModified; QString projectId; @@ -332,7 +441,7 @@ 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(m_userHash, projectName); + QByteArray projectData = m_serviceConnector.fetchUserProject(userHash, projectName); updatePopup("Caching user project..."); if (!m_projectManager->cacheProject(projectData, projectInfo)) { @@ -359,7 +468,7 @@ void Backend::runOnlineProject(const QString &url) initializeProjectManager(); emit popupOpen(); updatePopup("Downloading...", false); - QByteArray projectData = m_serviceConnector->fetchProject(url); + QByteArray projectData = m_serviceConnector.fetchProject(url); if (projectData.isEmpty()) { qCritical() << "Could not download project. Please check the logs for more information."; return; @@ -378,21 +487,19 @@ void Backend::runOnlineProject(const QString &url) emit popupClose(); } -void Backend::registerUser(const QUrl &url) +void Backend::updateUserProjectList() { - const QString userHash = url.toString().remove("qtdesignviewer://"); - qDebug() << "Registering User Hash: " << userHash; - m_userHash = userHash; - QSettings().setValue("user/hash", m_userHash); emit userRegistered(); - updateUserProjectList(); -} -void Backend::updateUserProjectList() -{ - qDebug() << "Fetching available project list for user: " << m_userHash; - m_serviceConnector.reset(new ServiceConnector); - QJsonArray projectList = m_serviceConnector->fetchUserProjectList(m_userHash); + const QString userHash = Backend::userHash(); + + if (userHash.isEmpty()) { + qWarning("User hash is not registered"); + return; + } + + qDebug() << "Fetching available project list for user:" << userHash; + QJsonArray projectList = m_serviceConnector.fetchUserProjectList(userHash); if (projectList.isEmpty()) { qCritical("Could not fetch available project list"); @@ -411,16 +518,17 @@ void Backend::updateUserProjectList() qDebug() << "--" << projectName; m_projectList << projectName; } + emit projectListChanged(); } void Backend::parseDesignViewerUrl(const QUrl &url) { - QString urlData = url.toString().remove("qtdesignviewer://"); + QString urlData = url.toString(); // urlData could be either a direct url to the project or a user hash // If it is a user hash, we register the user and fetch the project list // If it is a project url, we submit the url to the text field - // sample url: qtdesignviewer://https://<url>/<project_name>.qmlrc + // sample url: https://<url>/<project_name>.qmlrc // sample user hash: qtdesignviewer://17e8907b3b84029384hs8djshdu38476 if (urlData.isEmpty()) return; @@ -429,8 +537,10 @@ void Backend::parseDesignViewerUrl(const QUrl &url) emit urlUpdated(urlData); } else if (urlData.startsWith("https://")) { emit urlUpdated(urlData); - } else { + } else if (urlData.startsWith("qtdesignviewer://")) { qDebug() << "Registering user from QR code"; - registerUser(url); + setUserHash(url.toString().remove("qtdesignviewer://")); + } else { + qWarning() << "Unknown QR code data: " << urlData; } } diff --git a/src/backend.h b/src/backend.h index d4c08ef082bd818acdd5822c371e3cf83613d0cd..3363acd874112102d2153b32d74be7b47776ea26 100644 --- a/src/backend.h +++ b/src/backend.h @@ -59,7 +59,6 @@ class Backend : public QObject { Q_OBJECT Q_PROPERTY(QStringList projectList READ projectList NOTIFY projectListChanged FINAL) - Q_PROPERTY(QString userHash READ userHash FINAL) public: explicit Backend(QObject *parent = nullptr); @@ -71,7 +70,6 @@ public: } QStringList projectList() const { return m_projectList; } - QString userHash() const { return m_userHash; } private: // UI data @@ -80,15 +78,17 @@ private: QJsonArray m_projectListArray; // Other members - QString m_userHash; - QScopedPointer<ServiceConnector> m_serviceConnector; + ServiceConnector m_serviceConnector; QScopedPointer<ProjectManager> m_projectManager; QScopedPointer<DesignStudioConnector> m_designStudioConnector; QThread m_dsConnectorThread; - QTimer m_backgroundTimer; + // QR code scanner QSharedPointer<QMediaCaptureSession> m_captureSession; + // Settings + QTimer m_backgroundTimer; + // member functions void updateUserProjectList(); void updatePopup(const QString &text, bool indeterminate = true); @@ -106,9 +106,11 @@ signals: void userRegistered(); void networkUpdated(QString); void urlUpdated(QString); + void userHashChanged(QString); public slots: void scanQrCode(); + void openCamera(); void runOnlineProject(const QString &url); void runUserProject(const QString &projectName); @@ -118,15 +120,20 @@ public slots: void initDesignStudioConnector(); void parseDesignViewerUrl(const QUrl &url); - void registerUser(const QUrl &url); - // settings - void updateInBackground(const bool &enabled); - void cacheDemoProjects(const bool &enabled); - void cacheUserProjects(const bool &enabled); + // settings - setters + void setUpdateInBackground(const bool &enabled); + void setAutoScaleProject(const bool &enabled); + void setUserHash(const QString &userHash); + + // settings - getters + bool updateInBackground(); + bool autoScaleProject(); + QString userHash(); private slots: void initializeProjectManager(); + void enableBackgroundUpdate(const bool &enabled); }; #endif // DV_ANDROID_H diff --git a/src/main.cpp b/src/main.cpp index a4cc5408f20cb46cc3569bef758d62b11f779c79..270357215b77f6eb4694d92ef6016ac32fc194d9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -27,7 +27,6 @@ #include <QApplication> #include <QMessageBox> -#include <QPermission> #include <QQmlContext> #include "backend.h" @@ -65,8 +64,10 @@ void messageHandler(QtMsgType type, const QMessageLogContext &context, const QSt newLog += logPrefix + localMsg + logSuffix + "\n"; __android_log_print(ANDROID_LOG_DEBUG, "Qt_UI_Viewer", "%s", qPrintable(newLog)); - // only show critical and fatal messages in the UI - if (type == QtCriticalMsg || type == QtFatalMsg) { + if (type == QtWarningMsg) { + if (backend) + backend->setLogs(appLogs += newLog); + } else if (type == QtCriticalMsg || type == QtFatalMsg) { QMessageBox msgBox{QMessageBox::Critical, "Critical:", msg, QMessageBox::Ok}; msgBox.exec(); if (backend) @@ -85,25 +86,6 @@ int main(int argc, char *argv[]) QQuickView view; backend = new Backend(); - // request permissions - QCameraPermission permission; - switch (app.checkPermission(permission)) { - case Qt::PermissionStatus::Granted: - break; - case Qt::PermissionStatus::Undetermined: - case Qt::PermissionStatus::Denied: - app.requestPermission(permission, [](const QPermission &permission) { - if (permission.status() == Qt::PermissionStatus::Denied) { - QMessageBox msgBox{QMessageBox::Critical, - "Critical:", - "Camera permission denied", - QMessageBox::Ok}; - msgBox.exec(); - } - }); - break; - } - view.engine()->rootContext()->setContextProperty("backend", backend); view.setSource(QUrl(QStringLiteral("qrc:/main.qml"))); view.setResizeMode(QQuickView::SizeRootObjectToView); diff --git a/src/projectManager.cpp b/src/projectManager.cpp index 1b3867cd5bf8e735bb0d3ecf10561ce256762ce8..b60006e7c3d305f2113d3503d47393404e671626 100644 --- a/src/projectManager.cpp +++ b/src/projectManager.cpp @@ -46,8 +46,9 @@ #include <QtGui/private/qzipreader_p.h> #endif -ProjectManager::ProjectManager(QObject *parent) +ProjectManager::ProjectManager(const bool &autoScaleProject, QObject *parent) : QObject(parent) + , m_autoScaleProject(autoScaleProject) , m_projectCachePath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)) , m_demoProjectCachePath(m_projectCachePath + "/demoProjects") { @@ -512,6 +513,9 @@ bool ProjectManager::runDemoProject(const QString &projectName) void ProjectManager::orientateWindow(Qt::ScreenOrientation orientation) { + if (!m_autoScaleProject) + return; + QQuickItem *contentItem = m_quickWindow->contentItem(); QQuickItem *childItem{contentItem->childItems().at(0)}; diff --git a/src/projectManager.h b/src/projectManager.h index 3b86a8eb825127c3a25ccbacc56b6aee40b9875c..9cc3b952edeee2656261a2828270b5f96a3553ff 100644 --- a/src/projectManager.h +++ b/src/projectManager.h @@ -37,7 +37,7 @@ class ProjectManager : public QObject { Q_OBJECT public: - explicit ProjectManager(QObject *parent = nullptr); + explicit ProjectManager(const bool &autoScaleProject = true, QObject *parent = nullptr); ~ProjectManager(); QString unpackProject(const QByteArray &project, bool extractZip = false); @@ -64,6 +64,7 @@ private: QString m_projectPath; const QString m_projectCachePath; const QString m_demoProjectCachePath; + const bool m_autoScaleProject; // Qml related members QScopedPointer<QQmlEngine> m_qmlEngine; diff --git a/src/serviceConnector.cpp b/src/serviceConnector.cpp index f19d8ab681cca2b15f886764c7f769fd22f8a52f..01ec60a0db378509a0939a74a3d088687012f80e 100644 --- a/src/serviceConnector.cpp +++ b/src/serviceConnector.cpp @@ -31,7 +31,7 @@ #include <QJsonDocument> #include <QJsonObject> -QByteArray ServiceConnector::fetchResource(const QString &url) +QByteArray ServiceConnector::fetchResource(const QString &url, const bool quite) { qDebug() << "Fetching resource from" << url; @@ -41,9 +41,11 @@ QByteArray ServiceConnector::fetchResource(const QString &url) QObject::connect(reply.data(), &QNetworkReply::sslErrors, this, - [&](const QList<QSslError> &errors) - { - qCritical() << errors.first().errorString(); + [&](const QList<QSslError> &errors) { + if (!quite) + qCritical() << errors.first().errorString(); + else + qWarning() << errors.first().errorString(); }); QEventLoop loop; @@ -51,18 +53,23 @@ QByteArray ServiceConnector::fetchResource(const QString &url) QObject::connect(reply.data(), &QNetworkReply::downloadProgress, this, - [&](qint64 bytesReceived, qint64 bytesTotal) - { - float percentage = roundf((float)bytesReceived / (float)bytesTotal * 100); - qDebug() << "Download progress" << QString::number(percentage) << "% -" << QString::number(bytesReceived) << "/" << QString::number(bytesTotal); + [&](qint64 bytesReceived, qint64 bytesTotal) { + float percentage = roundf((float) bytesReceived / (float) bytesTotal * 100); + qDebug() << "Download progress" << QString::number(percentage) << "% -" + << QString::number(bytesReceived) << "/" + << QString::number(bytesTotal); emit downloadProgress(percentage); }); loop.exec(); - if (reply->error() != QNetworkReply::NoError) - qCritical() << reply->errorString(); - else + if (reply->error() != QNetworkReply::NoError) { + if (!quite) + qCritical() << reply->errorString(); + else + qWarning() << reply->errorString(); + } else { qDebug() << "Resource fetched successfully"; + } return reply->readAll(); } @@ -88,9 +95,11 @@ QByteArray ServiceConnector::fetchUserProject(const QString &userHash, const QSt QJsonArray ServiceConnector::fetchUserProjectList(const QString &userHash) { - auto reply = fetchResource("https://designviewer.qt.io/api/v1/qmlrc/list/" + userHash + "?key=818815"); + auto reply = fetchResource("https://designviewer.qt.io/api/v1/qmlrc/list/" + userHash + + "?key=818815", + true); + if (reply.size() == 0) { - qCritical("Could not fetch available project list"); return QJsonArray(); } @@ -108,7 +117,6 @@ QJsonArray ServiceConnector::fetchUserDemoList() { auto reply = fetchResource("https://designviewer.qt.io/api/v1/demos"); if (reply.size() == 0) { - qCritical("Could not fetch available demo list"); return QJsonArray(); } diff --git a/src/serviceConnector.h b/src/serviceConnector.h index 7af0d21cd583126be26014704d90d5585ba414d4..ad0c4d9b5beafb7915fc15622195a44c94fd0cb4 100644 --- a/src/serviceConnector.h +++ b/src/serviceConnector.h @@ -40,7 +40,7 @@ public: private: QNetworkAccessManager m_manager; - QByteArray fetchResource(const QString &url); + QByteArray fetchResource(const QString &url, const bool quite = false); signals: void downloadProgress(float percentage); diff --git a/ui/HomePage.qml b/ui/HomePage.qml index add017c5e392360228402655c4af2b167d92bcbd..b4984825fc787926ce2aaab202f3d5c110760de3 100644 --- a/ui/HomePage.qml +++ b/ui/HomePage.qml @@ -5,24 +5,21 @@ import QtQuick.Layouts Item { id: homePage - //width: 400 - //height: 740 ColumnLayout { anchors.fill: parent - Item { id: item2 Layout.preferredWidth: 10 - Layout.preferredHeight: 10 + Layout.preferredHeight: 3 Layout.fillWidth: true Layout.fillHeight: true } Text { id: qrCodeStatus - text: qsTr("No user code is registered.\nTo access your shared projects;") + text: qsTr("No user code is registered. To access your shared projects;") font.pixelSize: 12 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter @@ -39,7 +36,7 @@ Item { Text { id: qrCodeInstructions - text: qsTr("1. Open Design Studio (4.4 or later)\n2. Open any project\n3. Click \"File\" menu from top\n4. Select \"Share Application Online\"\n5. Scan QR code with your camera or any QR reader app") + text: qsTr("1. Open a project with Design Studio (4.4 or later)\n2. Click \"File\" menu from top and select \"Share Application Online\"\n3. Scan the QR code on the screen") font.pixelSize: 12 horizontalAlignment: Text.AlignHCenter verticalAlignment: Text.AlignVCenter @@ -61,40 +58,39 @@ Item { Layout.fillWidth: true Layout.fillHeight: true } + ColumnLayout { id: column2 Layout.fillWidth: true ComboBox { id: projectList Layout.fillWidth: true + enabled: backend.userHash() !== '' onCurrentIndexChanged: { displayText = textAt(currentIndex) - downloadUserProject.enabled = true - } - onModelChanged: { - if (model.count > 0) { - currentIndex = 0 - } } model: backend.projectList - down: false - displayText: "Select project..." + displayText: "Scan QR code to access your projects"; currentIndex: -1 Layout.preferredHeight: 50 + Connections { + target: backend + function onUserRegistered(){ + projectList.enabled = true; + } + } } Button { id: downloadUserProject text: qsTr("Run Project") onClicked: backend.runUserProject(projectList.currentText) - enabled: backend.userHash !== '' + enabled: backend.userHash() !== '' Layout.fillWidth: true Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter } } - - Item { id: item3 Layout.fillHeight: true @@ -103,11 +99,10 @@ Item { Layout.preferredWidth: 10 } - - ColumnLayout { id: column Layout.fillWidth: true + visible: false Text { id: downloadInstructions diff --git a/ui/SettingsPage.qml b/ui/SettingsPage.qml index 7e86b60d41d8d9d0c9366a6997cf2bb98a5043cb..7bb4ceb904d87ebd5bf1b9d9f50b69f1233604a4 100644 --- a/ui/SettingsPage.qml +++ b/ui/SettingsPage.qml @@ -24,7 +24,8 @@ Item { id: checkBox text: qsTr("Update user projects in the backgroud") font.pointSize: 15 - onCheckStateChanged: backend.updateInBackground(checkState) + onCheckStateChanged: backend.setUpdateInBackground(checkState) + checkState: backend.updateInBackground() ? Qt.Checked : Qt.Unchecked } Text{ @@ -33,31 +34,20 @@ Item { font.pointSize: 12 } -// CheckBox { -// id: checkBox2 -// text: qsTr("Cache user projects") -// font.pointSize: 15 -// onCheckStateChanged: backend.cacheUserProjects(checkState) -// } - -// Text{ -// leftPadding: 45 -// text: qsTr("Downloads the user projects each time if disabled") -// font.pointSize: 12 -// } + CheckBox { + id: checkBox2 + text: qsTr("Auto scale the project") + font.pointSize: 15 + onCheckStateChanged: backend.setAutoScaleProject(checkState) + checkState: backend.autoScaleProject() ? Qt.Checked : Qt.Unchecked -// CheckBox { -// id: checkBox3 -// text: qsTr("Cache demo projects") -// font.pointSize: 15 -// onCheckStateChanged: backend.cacheDemoProjects(checkState) -// } + } -// Text{ -// leftPadding: 45 -// text: qsTr("Downloads the demo projects each time if disabled") -// font.pointSize: 12 -// } + Text{ + leftPadding: 45 + text: qsTr("Scales the project to fit it to the current display and orientation") + font.pointSize: 12 + } } Item { @@ -67,13 +57,5 @@ Item { Layout.preferredHeight: 10 Layout.preferredWidth: 10 } - -// Button { -// id: downloadButton -// text: qsTr("Save") -// onClicked: backend.saveSettings(checkBox.checked) -// Layout.fillWidth: true -// Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter -// } } } diff --git a/ui/main.qml b/ui/main.qml index 2e5491dc7b7af550e80ed97da932c0d4efde4f6c..1e76caf38d0a9965ac7c111d87815ca7ae75d553 100644 --- a/ui/main.qml +++ b/ui/main.qml @@ -2,7 +2,6 @@ import QtQuick 6.4 import QtQuick.Controls 6.4 import QtQuick.Controls.Material as M import QtQuick.Layouts -//import QtQuick.Window 2.2 Rectangle { id: root @@ -11,6 +10,7 @@ Rectangle { color: "#EAEAEA" state: "vertical" + M.Material.theme: M.Material.Light M.Material.accent: M.Material.Blue M.Material.primary: M.Material.Blue @@ -26,7 +26,7 @@ Rectangle { Text { id: qdvLabel - text: qsTr("Qt UI Viewer for Android") + text: qsTr("Qt UI Viewer") anchors.top: parent.bottom font.pixelSize: 12 anchors.topMargin: -22 @@ -124,11 +124,12 @@ Rectangle { states: [ State { name: "vertical" - when: root.width >= 400 + when: root.height >= 400 + }, State { name: "horizontal" - when: root.width < 400 + when: root.height < 400 PropertyChanges { target: qdsicon1 @@ -145,30 +146,25 @@ Rectangle { target: stackLayout anchors.topMargin: 20 } - } ] - Drawer { + Drawer { id: drawer width: 150 height: root.height + ScrollView { + id: scrollview + anchors.fill: parent ColumnLayout { id: column - anchors.fill: parent - anchors.bottomMargin: 31 + anchors.fill: drawer anchors.rightMargin: 10 anchors.leftMargin: 10 - spacing: 5 - - Image { - id: qdsicon2 - source: "content/images/appicon.png" - sourceSize.width: drawer.width / 2 - anchors.horizontalCenter: parent.horizontalCenter - } + width: Math.max(implicitWidth, drawer.availableWidth) + height: Math.max(implicitHeight, drawer.availableHeight) TabButton { id: home @@ -207,6 +203,7 @@ Rectangle { Layout.fillWidth: true checkable: true autoExclusive: true + Connections { target: logs function onClicked(){ @@ -261,6 +258,7 @@ Rectangle { } } } + } } Button {