Skip to content
Snippets Groups Projects
Commit 678bd375 authored by Burak Hançerli's avatar Burak Hançerli :headphones:
Browse files

QDS-11947 Clean cached user project

parent 32be9c2f
No related branches found
No related tags found
1 merge request!41QDS-11947 Clean cached user project
Pipeline #67754 passed
......@@ -8,9 +8,13 @@ set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
add_compile_options(-Wall -Wextra)
endif()
find_package(
QT NAMES Qt6
COMPONENTS Core Widgets Quick Gui Qml Multimedia MultimediaWidgets Concurrent
......@@ -35,9 +39,10 @@ qt_add_executable(${PROJECT_NAME}
src/importdummy.qml
src/main.cpp
src/backend.cpp src/backend.h
src/serviceConnector.cpp src/serviceConnector.h
src/projectManager.cpp src/projectManager.h
src/dsConnector.cpp src/dsConnector.h
src/serviceconnector.cpp src/serviceconnector.h
src/projectmanager.cpp src/projectmanager.h
src/dsconnector.cpp src/dsconnector.h
src/qrscanner.cpp src/qrscanner.h
3rdparty/zxing-cpp/example/ZXingQtReader.h
ui/main.qml
ui/resources.qrc
......
......@@ -24,25 +24,14 @@
****************************************************************************/
#include "backend.h"
#include "qapplication.h"
#include <QCameraDevice>
#include <QDesktopServices>
#include <QElapsedTimer>
#include <QEventLoop>
#include <QFileInfo>
#include <QGuiApplication>
#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"
using namespace ZXingQt;
Backend::Backend(QObject *parent)
: QObject(parent)
......@@ -147,113 +136,13 @@ void Backend::updatePopup(const QString &text, bool indeterminate)
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);
m_captureSession->camera()->setFocusMode(QCamera::FocusModeAuto);
CustomVideoWidget *videoWidget = qobject_cast<CustomVideoWidget *>(
m_captureSession->videoOutput());
connect(m_captureSession->videoSink(),
&QVideoSink::videoFrameChanged,
this,
[&](const QVideoFrame &frame) {
static int i = 0;
static QAtomicInt running = 0;
if (i++ < 20 || running > 0) {
return;
}
i = 0;
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();
// 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();
}
m_qrScanner.reset(new QrScanner);
connect(m_qrScanner.data(), &QrScanner::qrCodeScanned, this, [&](const QString &qrCode) {
qDebug() << "QR code scanned:" << qrCode;
parseDesignViewerUrl(QUrl(qrCode));
m_qrScanner.reset();
});
// stop camera when video widget is closed
connect(videoWidget, &CustomVideoWidget::closed, this, [&] {
qDebug() << "Video widget closed. Clearing capture session";
m_captureSession->camera()->stop();
m_captureSession->camera()->deleteLater();
m_captureSession->videoOutput()->deleteLater();
m_captureSession.clear();
});
videoWidget->setWindowFlags(Qt::Window | Qt::WindowStaysOnTopHint);
videoWidget->show();
m_captureSession->camera()->start();
m_qrScanner->scanQrCode();
}
void Backend::initializeProjectManager()
......@@ -382,9 +271,7 @@ void Backend::clearDemoCaches()
{
emit popupOpen();
updatePopup("Clearing demo caches...");
m_projectManager.reset(new ProjectManager);
m_projectManager->clearDemoCaches();
m_projectManager.reset();
ProjectManager().clearDemoCaches();
emit popupClose();
}
......@@ -500,6 +387,16 @@ void Backend::updateUserProjectList()
const QString projectName{project.toObject().value("appName").toString()};
qDebug() << "--" << projectName;
}
// check if any project is removed on the cloud
for (const auto &project : m_projectList) {
const QString projectName{project.toObject().value("appName").toString()};
if (!projectList.value().contains(project)) {
qDebug() << "Project removed:" << projectName << ". Removing from cache...";
// remove the project from the cache
ProjectManager().clearCachedProject(project.toObject());
}
}
}
// we need to set m_projectList even if it is empty
......
......@@ -26,34 +26,12 @@
#ifndef DV_ANDROID_H
#define DV_ANDROID_H
#include <QCamera>
#include <QImageCapture>
#include <QMediaCaptureSession>
#include <QThread>
#include <QVideoWidget>
#include <QWidget>
#include "dsConnector.h"
#include "projectManager.h"
#include "serviceConnector.h"
#include <QLabel>
#include <QVBoxLayout>
class CustomVideoWidget : public QVideoWidget
{
Q_OBJECT
public:
explicit CustomVideoWidget(QWidget *parent = nullptr)
: QVideoWidget(parent)
{}
~CustomVideoWidget() override {}
void closeEvent(QCloseEvent *event) override { emit closed(); }
signals:
void closed();
};
#include "dsconnector.h"
#include "projectmanager.h"
#include "qrscanner.h"
#include "serviceconnector.h"
class Backend : public QObject
{
......@@ -78,13 +56,12 @@ private:
QJsonArray m_projectList;
// Other members
ServiceConnector m_serviceConnector;
QThread m_dsConnectorThread;
QScopedPointer<ProjectManager> m_projectManager;
QScopedPointer<DesignStudioConnector> m_designStudioConnector;
QThread m_dsConnectorThread;
// QR code scanner
QSharedPointer<QMediaCaptureSession> m_captureSession;
QScopedPointer<QrScanner> m_qrScanner;
// Settings
QTimer m_backgroundTimer;
......@@ -117,7 +94,6 @@ signals:
public slots:
QString buildInfo() const { return m_buildInfo; }
void scanQrCode();
void openCamera();
void runOnlineProject(const QString &url);
void runUserProject(const QString &projectName, const QString &password);
......
......@@ -23,7 +23,7 @@
**
****************************************************************************/
#include "dsConnector.h"
#include "dsconnector.h"
#include <QNetworkInterface>
......
File moved
......@@ -23,7 +23,7 @@
**
****************************************************************************/
#include "projectManager.h"
#include "projectmanager.h"
#include <QBuffer>
#include <QDir>
......@@ -48,9 +48,9 @@
ProjectManager::ProjectManager(const bool &autoScaleProject, QObject *parent)
: QObject(parent)
, m_autoScaleProject(autoScaleProject)
, m_projectCachePath(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation))
, m_demoProjectCachePath(m_projectCachePath + "/demoProjects")
, m_autoScaleProject(autoScaleProject)
{
qDebug() << "ProjectManager created.";
qDebug() << "Project cache path: " << m_projectCachePath;
......@@ -399,6 +399,20 @@ bool ProjectManager::isProjectCached(const QJsonObject &projectInfo)
return true;
}
void ProjectManager::clearCachedProject(const QJsonObject &projectInfo)
{
const QString projectId = projectInfo.value("id").toString();
qDebug() << "Clearing cache for project " << projectId;
const QString cachePath = m_projectCachePath + "/" + projectId;
if (!QDir(cachePath).exists()) {
qDebug() << "Project " << projectId << " is not cached";
}
qDebug() << "Removing cache for project " << projectId;
QDir(cachePath).removeRecursively();
}
bool ProjectManager::runCachedProject(const QJsonObject &projectInfo)
{
const QString projectId = projectInfo.value("id").toString();
......
......@@ -46,6 +46,7 @@ public:
bool cacheProject(const QByteArray &projectData, const QJsonObject &projectInfo);
bool isProjectCached(const QJsonObject &projectInfo);
bool runCachedProject(const QJsonObject &projectInfo);
void clearCachedProject(const QJsonObject &projectInfo);
bool cacheDemoProject(const QByteArray &projectData, const QJsonObject &projectInfo);
bool isDemoProjectCached(const QJsonObject &projectName);
......
/****************************************************************************
**
** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Design Viewer of the Qt Toolkit.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#include "qrscanner.h"
#include <QApplication>
#include <QCamera>
#include <QCameraDevice>
#include <QElapsedTimer>
#include <QImageCapture>
#include <QMediaDevices>
#include <QMessageBox>
#include <QPermission>
#include <QVideoSink>
#include <QtConcurrent>
#include "../3rdparty/zxing-cpp/example/ZXingQtReader.h"
using namespace ZXingQt;
QrScanner::~QrScanner()
{
if (m_captureSession) {
m_captureSession->camera()->stop();
m_captureSession->camera()->deleteLater();
m_captureSession->videoOutput()->deleteLater();
m_captureSession.clear();
}
}
void QrScanner::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 QrScanner::openCamera()
{
// start camera
m_captureSession.reset(new QMediaCaptureSession(this));
m_captureSession->setCamera(new QCamera(this));
m_captureSession->setVideoOutput(new CustomVideoWidget);
m_captureSession->camera()->setFocusMode(QCamera::FocusModeAuto);
CustomVideoWidget *videoWidget = qobject_cast<CustomVideoWidget *>(
m_captureSession->videoOutput());
connect(m_captureSession->videoSink(),
&QVideoSink::videoFrameChanged,
this,
[&](const QVideoFrame &frame) {
static int i = 0;
static QAtomicInt running = 0;
if (i++ < 20 || running > 0) {
return;
}
i = 0;
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();
// 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()));
emit qrCodeScanned(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();
m_captureSession->camera()->deleteLater();
m_captureSession->videoOutput()->deleteLater();
m_captureSession.clear();
});
videoWidget->setWindowFlags(Qt::Window | Qt::WindowStaysOnTopHint);
videoWidget->show();
m_captureSession->camera()->start();
}
/****************************************************************************
**
** Copyright (C) 2024 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the Qt Design Viewer of the Qt Toolkit.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3 as published by the Free Software
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
**
****************************************************************************/
#pragma once
#include <QMediaCaptureSession>
#include <QVideoWidget>
class CustomVideoWidget : public QVideoWidget
{
Q_OBJECT
public:
explicit CustomVideoWidget(QWidget *parent = nullptr)
: QVideoWidget(parent)
{}
~CustomVideoWidget() override {}
void closeEvent(QCloseEvent *) override { emit closed(); }
signals:
void closed();
};
class QrScanner : public QObject
{
Q_OBJECT
public:
~QrScanner();
void scanQrCode();
private:
QSharedPointer<QMediaCaptureSession> m_captureSession;
void openCamera();
signals:
void qrCodeScanned(const QString &qrCode);
};
......@@ -23,7 +23,7 @@
**
****************************************************************************/
#include "serviceConnector.h"
#include "serviceconnector.h"
#include <QNetworkAccessManager>
#include <QNetworkReply>
......
File moved
......@@ -26,7 +26,7 @@ Rectangle {
Text {
id: qdvLabel
text: qsTr("Qt UI Viewer2")
text: qsTr("Qt UI Viewer")
anchors.top: parent.bottom
font.pixelSize: 12
anchors.topMargin: -22
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment