From bf94b2185528307a93734bf498129684a92c03f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Burak=20Han=C3=A7erli?= <burak.hancerli@qt.io> Date: Mon, 16 Oct 2023 12:33:23 +0000 Subject: [PATCH] QDS-10485 Implement QR code integration --- CMakeLists.txt | 1 + android/AndroidManifest.xml | 54 +++++++++---------------------- src/backend.cpp | 63 +++++++++++++++++++++++++++++++++++-- src/backend.h | 9 ++++++ src/importdummy.qml | 35 +++++++++++++++++++++ src/main.cpp | 13 ++------ ui/main.qml | 63 +++++++++++++++++++++++++++---------- 7 files changed, 170 insertions(+), 68 deletions(-) create mode 100644 src/importdummy.qml diff --git a/CMakeLists.txt b/CMakeLists.txt index 1df7557..16ba4fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,6 +29,7 @@ if(QT_VERSION VERSION_LESS QT_MINIMUM_VERSION) endif() qt_add_executable(${PROJECT_NAME} + src/importdummy.qml src/main.cpp src/backend.cpp src/backend.h ui/main.qml diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index f4f4c4b..ea54fe1 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -1,47 +1,23 @@ <?xml version="1.0"?> -<manifest xmlns:android="http://schemas.android.com/apk/res/android" - package="io.qt.qtdesignviewer" - android:installLocation="auto" - android:versionCode="1" - android:versionName="1.2"> +<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="io.qt.qtdesignviewer" android:installLocation="auto" android:versionCode="1" android:versionName="1.2"> <!-- %%INSERT_PERMISSIONS --> <!-- %%INSERT_FEATURES --> - <supports-screens - android:anyDensity="true" - android:largeScreens="true" - android:normalScreens="true" - android:smallScreens="true" /> - <application - android:name="org.qtproject.qt.android.bindings.QtApplication" - android:extractNativeLibs="true" - android:hardwareAccelerated="true" - android:label="Qt Design Viewer" - android:icon="@mipmap/app_icon" - android:requestLegacyExternalStorage="true" - android:allowNativeHeapPointerTagging="false"> - <activity - android:name="org.qtproject.qt.android.bindings.QtActivity" - android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" - android:label="Qt Design Viewer" - android:launchMode="singleTop" - android:screenOrientation="unspecified" - android:exported="true"> + <supports-screens android:anyDensity="true" android:largeScreens="true" android:normalScreens="true" android:smallScreens="true"/> + <application android:name="org.qtproject.qt.android.bindings.QtApplication" android:extractNativeLibs="true" android:hardwareAccelerated="true" android:label="Qt Design Viewer" android:requestLegacyExternalStorage="true" android:allowNativeHeapPointerTagging="false"> + <activity android:name="org.qtproject.qt.android.bindings.QtActivity" android:configChanges="orientation|uiMode|screenLayout|screenSize|smallestScreenSize|layoutDirection|locale|fontScale|keyboard|keyboardHidden|navigation|mcc|mnc|density" android:label="Qt Design Viewer" android:launchMode="singleTop" android:screenOrientation="unspecified" android:exported="true"> <intent-filter> - <action android:name="android.intent.action.MAIN" /> - <category android:name="android.intent.category.LAUNCHER" /> + <action android:name="android.intent.action.MAIN"/> + <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> - - <meta-data - android:name="android.app.lib_name" - android:value="-- %%INSERT_APP_LIB_NAME%% --" /> - - <meta-data - android:name="android.app.arguments" - android:value="-- %%INSERT_APP_ARGUMENTS%% --" /> - - <meta-data - android:name="android.app.extract_android_style" - android:value="minimal" /> + <intent-filter> + <action android:name="android.intent.action.VIEW"/> + <category android:name="android.intent.category.DEFAULT"/> + <category android:name="android.intent.category.BROWSABLE"/> + <data android:scheme="qtdesignviewer"/> + </intent-filter> + <meta-data android:name="android.app.lib_name" android:value="-- %%INSERT_APP_LIB_NAME%% --"/> + <meta-data android:name="android.app.arguments" android:value="-- %%INSERT_APP_ARGUMENTS%% --"/> + <meta-data android:name="android.app.extract_android_style" android:value="minimal"/> </activity> </application> </manifest> diff --git a/src/backend.cpp b/src/backend.cpp index 0f08497..d946eaf 100644 --- a/src/backend.cpp +++ b/src/backend.cpp @@ -24,29 +24,38 @@ ****************************************************************************/ #include "backend.h" +#include "qapplication.h" #if !defined(Q_OS_WASM) #include <QBuffer> +#include <QDesktopServices> #include <QDirIterator> #include <QEventLoop> #include <QFileInfo> #include <QGuiApplication> +#include <QJsonArray> +#include <QJsonDocument> +#include <QJsonObject> #include <QMessageBox> #include <QNetworkReply> #include <QQuickItem> #include <QRandomGenerator> #include <QRegularExpression> #include <QResource> +#include <QSettings> #include <QSslSocket> #include <QTemporaryDir> #include <QTemporaryFile> +#include <QtCore/private/qandroidextras_p.h> #include <QtGui/private/qzipreader_p.h> #define QSTRN QString::number Backend::Backend(QObject *parent) { + QDesktopServices::setUrlHandler("qtdesignviewer", this, "registerUser"); + const QRect screenGeometry = QGuiApplication::primaryScreen()->geometry(); printLog("Qt Design Viewer"); @@ -56,9 +65,25 @@ Backend::Backend(QObject *parent) printLog("-- Screen height: " + QSTRN(screenGeometry.height())); printLog("-- Screen width: " + QSTRN(screenGeometry.width())); - m_buildInfo = QCoreApplication::applicationVersion() + "\n" + "Qt " + QString(QT_VERSION_STR) - + " - OpenSSL support: " + QVariant(QSslSocket::supportsSsl()).toString(); +#ifdef QT_DEBUG + QString buildType = "Debug"; +#else + QString buildType = "Release"; +#endif + m_buildInfo = QCoreApplication::applicationVersion() + "\nQt " + QString(QT_VERSION_STR) + " - " + + buildType + " Build" + + "\nOpenSSL support: " + QVariant(QSslSocket::supportsSsl()).toString(); emit buildInfoChanged(); + + QSettings settings; + m_userHash = settings.value("user/hash").toString(); + if (m_userHash.isEmpty()) + printLog("User Hash is not registered. Scan QR code to register."); + else { + printLog("User Hash: " + m_userHash); + updateUserProjectList(); + } + printLog("Initialization complete"); } @@ -424,4 +449,38 @@ void Backend::downloadAndRun(const QString &url) showAppWindow(); } +void Backend::registerUser(const QUrl &url) +{ + const QString userHash = url.toString().remove("qtdesignviewer://"); + printLog("Registering User Hash: " + userHash); + m_userHash = userHash; + QSettings().setValue("user/hash", m_userHash); + updateUserProjectList(); +} + +void Backend::updateUserProjectList() +{ + printLog("Fetching available project list for user: " + m_userHash); + auto reply = fetchResource("https://designviewer.qt.io/api/v1/qmlrc/list/" + m_userHash + + "?key=818815"); + if (reply->error() != QNetworkReply::NoError) { + printErr("Could not fetch available project list"); + return; + } + + QJsonArray projectList = QJsonDocument::fromJson(reply->readAll()) + .object() + .value("data") + .toObject() + .value("packages") + .toArray(); + printLog("List of available projects fetched:"); + for (const auto &project : projectList) { + const QString projectName{project.toObject().value("appName").toString()}; + printLog("-- " + projectName); + m_projectList << projectName; + } + emit projectListChanged(); +} + #endif // !defined(Q_OS_WASM) diff --git a/src/backend.h b/src/backend.h index be1ccbb..7d4a634 100644 --- a/src/backend.h +++ b/src/backend.h @@ -40,18 +40,23 @@ class Backend : public QObject Q_PROPERTY(QString logs READ logs NOTIFY logsChanged) Q_PROPERTY(QString buildInfo READ buildInfo NOTIFY buildInfoChanged) Q_PROPERTY(int downloadProgress READ downloadProgress NOTIFY downloadProgressChanged FINAL) + Q_PROPERTY(QStringList projectList READ projectList NOTIFY projectListChanged FINAL) + Q_PROPERTY(QString userHash READ userHash FINAL) public: explicit Backend(QObject *parent = nullptr); QString logs() const { return m_logs; } QString buildInfo() const { return m_buildInfo; } int downloadProgress() const { return m_downloadProgress; } + QStringList projectList() const { return m_projectList; } + QString userHash() const { return m_userHash; } private: // UI data QString m_logs; QString m_buildInfo; int m_downloadProgress = 0; + QStringList m_projectList; // Qml related members QQmlEngine m_qmlEngine; @@ -62,6 +67,7 @@ private: QNetworkAccessManager m_nam; QByteArray m_projectData; QString m_projectPath; + QString m_userHash; // member logger functions void printLog(const QString &message); @@ -76,14 +82,17 @@ private: QString findFile(const QString &dir, const QString &filter); void parseQmlprojectFile(const QString &fileName, QString *mainFile, QStringList *importPaths); bool runProject(const QByteArray &projectData, const QString &projectName); + void updateUserProjectList(); signals: void logsChanged(); void buildInfoChanged(); void downloadProgressChanged(); + void projectListChanged(); public slots: void downloadAndRun(const QString &url); + void registerUser(const QUrl &url); private slots: void orientateWindow(Qt::ScreenOrientation orientation); diff --git a/src/importdummy.qml b/src/importdummy.qml new file mode 100644 index 0000000..085643d --- /dev/null +++ b/src/importdummy.qml @@ -0,0 +1,35 @@ +// Hack to force the qml plugins to be linked statically + +import QtQuick +import QtQuick.Controls + +import QtQml +import QtQml.Models +import QtQml.StateMachine + +import QtQuick3D +import QtQuick3D.AssetUtils +import QtQuick3D.Effects +import QtQuick3D.Helpers +import QtQuick3D.ParticleEffects +import QtQuick3D.Particles3D +import QtQuick.VirtualKeyboard + +import QtQuick.Studio.Application +import QtQuick.Studio.Components +import QtQuick.Studio.Effects +import QtQuick.Studio.EventSimulator +import QtQuick.Studio.EventSystem +import QtQuick.Studio.LogicHelper +import QtQuick.Studio.MultiText + +import QtQuickUltralite.Extras +import QtQuickUltralite.Layers + +import FlowView + +ApplicationWindow { + visible: true + width: 640 + height: 480 +} diff --git a/src/main.cpp b/src/main.cpp index e9d8987..148e358 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -32,15 +32,10 @@ int main(int argc, char *argv[]) { - qDebug().noquote() << QString("Built on %1 %2\n").arg(__DATE__, __TIME__); - - QSurfaceFormat format = QSurfaceFormat::defaultFormat(); - format.setVersion(3, 0); - QSurfaceFormat::setDefaultFormat(format); - - QCoreApplication::setApplicationVersion(QString("Built on %1 %2").arg(__DATE__, __TIME__)); QApplication app(argc, argv); + QApplication::setOrganizationName("Qt"); QApplication::setApplicationName(QStringLiteral("Qt Design Viewer")); + QApplication::setApplicationVersion(QString("Built on %1 %2").arg(__DATE__, __TIME__)); Backend backend; @@ -50,9 +45,5 @@ int main(int argc, char *argv[]) view.setResizeMode(QQuickView::SizeRootObjectToView); view.showMaximized(); - QThread::msleep(2000); - - // backend.downloadAndRun("https://designviewer.qt.io/#17e8907b3b84b8206d45be4f551f4e25/" - // "MaterialBundle.qmlrc"); return app.exec(); } diff --git a/ui/main.qml b/ui/main.qml index 2266462..d034acb 100644 --- a/ui/main.qml +++ b/ui/main.qml @@ -1,10 +1,4 @@ -/* -This is a UI file (.ui.qml) that is intended to be edited in Qt Design Studio only. -It is supposed to be strictly declarative and only uses a subset of QML. If you edit -this file manually, you might introduce QML code that is not supported by Qt Design Studio. -Check out https://doc.qt.io/qtcreator/creator-quick-ui-forms.html for details on .ui.qml files. -*/ import QtQuick 6.4 import QtQuick.Controls 6.4 import QtQuick.Controls.Material @@ -52,11 +46,17 @@ Rectangle { placeholderText: qsTr("Enter URL") } - Button { - id: downloadButton - text: qsTr("Download and Run") - Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter - onClicked: backend.downloadAndRun(urlTextField.text) + RowLayout{ + id: rowLayout + anchors.left: parent.left + anchors.right: parent.right + Button { + id: downloadButton + Layout.fillWidth: true + text: qsTr("Download and Run") + Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter + onClicked: backend.downloadAndRun(urlTextField.text) + } } } @@ -65,7 +65,6 @@ Rectangle { width: 351 height: gridLayout.height anchors.top: parent.top - anchors.topMargin: 12 anchors.horizontalCenter: parent.horizontalCenter GridLayout { @@ -77,7 +76,7 @@ Rectangle { Image { id: qdsicon x: 47 - y: -23 + y: -48 width: 204 height: 202 source: "content/images/dvicon.png" @@ -109,23 +108,52 @@ Rectangle { } } + ComboBox { + id: projectList + height: 50 + anchors.left: parent.left + anchors.right: parent.right + anchors.top: header.bottom + down: false + anchors.topMargin: 15 + anchors.rightMargin: 22 + anchors.leftMargin: 22 + displayText: "Select project..." + model: backend.projectList + currentIndex: -1 + onCurrentIndexChanged: { + urlTextField.text = "https://designviewer.qt.io/qmlprojects/" + + backend.userHash + "/" + + textAt(currentIndex) + + ".qmlrc" + displayText = textAt(currentIndex) + } + } + Rectangle { id: log - visible: root.height > 620 + visible: true color: "#EAEAEA" anchors.left: parent.left anchors.right: parent.right - anchors.top: header.bottom + anchors.top: projectList.bottom anchors.bottom: bar.top - anchors.topMargin: 15 anchors.bottomMargin: 24 anchors.leftMargin: 22 ScrollView { id: scrollArea + visible: true anchors.fill: parent topPadding: 13.1 ScrollBar.vertical.policy: ScrollBar.AlwaysOn + Connections { + target: backend + function onLogsChanged() { + logTextArea.text = backend.logs + scrollArea.ScrollBar.vertical.position = 1.0 - scrollArea.ScrollBar.vertical.size + } + } TextArea { clip: false id: logTextArea @@ -139,4 +167,7 @@ Rectangle { } } } + + + } -- GitLab