1
0
mirror of https://gitlab.com/kelteseth/ScreenPlay.git synced 2024-11-06 19:12:30 +01:00

Move SDKConnectors SDKConnection class into seperate file

The next will be to merge SDKConnector into the ScreenPlayManager.

We now have the first version of bi directional messages. This is for updating values like
saving the current Widget position. We also save a SDKConnection shared reference inside
our ScreenPlayWallpaper or ScreenPlayWidget instance. So we now have all logic in these classes.
This commit is contained in:
Elias Steurer 2020-07-18 18:26:41 +02:00
parent 5f0d81df9e
commit 49b75a463a
16 changed files with 350 additions and 177 deletions

View File

@ -35,6 +35,7 @@ set(src main.cpp
src/sdkconnector.cpp
src/projectsettingslistmodel.cpp
src/screenplaymanager.cpp
src/sdkconnection.cpp
src/util.cpp
src/create.cpp)
@ -55,6 +56,7 @@ set(headers app.h
src/projectsettingslistitem.h
src/projectsettingslistmodel.h
src/screenplaymanager.h
src/sdkconnection.h
src/util.h
src/create.h)

View File

@ -136,7 +136,7 @@ Item {
onClicked: {
ScreenPlay.screenPlayManager.removeWallpaperAt(
monitorSelection.activeMonitors[0])
monitorSelection.deselectAll()
}
}
Button {

View File

@ -29,6 +29,7 @@ ScreenPlayManager::ScreenPlayManager(
, m_telemetry { telemetry }
, m_settings { settings }
{
QObject::connect(m_sdkconnector.get(), &SDKConnector::appConnected, this, &ScreenPlayManager::appConnected);
loadProfiles();
}
@ -104,6 +105,7 @@ void ScreenPlayManager::createWallpaper(
type,
m_settings->checkWallpaperVisible());
QObject::connect(wallpaper.get(), &ScreenPlayWallpaper::requestSave, this, &ScreenPlayManager::saveProfiles);
m_screenPlayWallpapers.append(wallpaper);
m_monitorListModel->setWallpaperActiveMonitor(wallpaper, monitorIndex);
increaseActiveWallpaperCounter();
@ -133,9 +135,27 @@ void ScreenPlayManager::createWidget(
qInfo() << "Path is empty, Abort! String: " << absoluteStoragePath;
return;
}
auto widget = std::make_shared<ScreenPlayWidget>(appID, m_globalVariables, position, path, previewImage, type);
QObject::connect(widget.get(), &ScreenPlayWidget::requestSave, this, &ScreenPlayManager::saveProfiles);
increaseActiveWidgetsCounter();
m_screenPlayWidgets.append(std::make_unique<ScreenPlayWidget>(appID, m_globalVariables, position, path, previewImage, type));
m_screenPlayWidgets.append(widget);
}
void ScreenPlayManager::appConnected(const std::shared_ptr<SDKConnection>& connection)
{
for (const auto& item : m_screenPlayWidgets) {
if (item->appID() == connection->appID()) {
item->setSDKConnection(connection);
return;
}
}
for (const auto& item : m_screenPlayWallpapers) {
if (item->appID() == connection->appID()) {
item->setSDKConnection(connection);
return;
}
}
}
/*!
@ -176,10 +196,10 @@ void ScreenPlayManager::removeAllWidgets()
{
if (!m_screenPlayWidgets.empty()) {
m_sdkconnector->closeAllWidgets();
m_screenPlayWidgets.clear();
saveProfiles();
setActiveWidgetsCounter(0);
}
}
/*!
@ -191,9 +211,8 @@ bool ScreenPlayManager::removeWallpaperAt(int index)
{
if (auto appID = m_monitorListModel->getAppIDByMonitorIndex(index)) {
if (!saveProfiles()) {
qWarning() << "Could not save profiles.json";
}
saveProfiles();
if (!m_sdkconnector->closeWallpaper(*appID)) {
qWarning() << "Could not close socket. Abort!";
return false;
@ -277,7 +296,7 @@ std::optional<std::shared_ptr<ScreenPlayWallpaper>> ScreenPlayManager::getWallpa
\brief Saves a given wallpaper \a newProfileObject to a \a profileName. We ignore the profileName argument
because we currently only support one profile. Returns \c true if successfuly saved to profiles.json, otherwise \c false.
*/
bool ScreenPlayManager::saveProfiles()
void ScreenPlayManager::saveProfiles()
{
QJsonArray wallpaper {};
@ -303,7 +322,7 @@ bool ScreenPlayManager::saveProfiles()
profile.insert("version", "1.0.0");
profile.insert("profiles", activeProfileList);
return Util::writeJsonObjectToFile({ m_globalVariables->localSettingsPath().toString() + "/profiles.json" }, profile);
Util::writeJsonObjectToFile({ m_globalVariables->localSettingsPath().toString() + "/profiles.json" }, profile);
}
bool ScreenPlayManager::removeWallpaperByAppID(const QString& appID)

View File

@ -91,6 +91,8 @@ signals:
void activeWidgetsCounterChanged(int activeWidgetsCounter);
public slots:
void saveProfiles();
// moc needs full enum namespace info see QTBUG-58454
void createWallpaper(
const ScreenPlay::InstalledType::InstalledType type,
@ -107,6 +109,8 @@ public slots:
const QString& previewImage,
const bool saveToProfilesConfigFile);
void appConnected(const std::shared_ptr<SDKConnection>& connection);
void removeAllWallpapers();
void removeAllWidgets();
bool removeWallpaperAt(const int index);
@ -166,7 +170,7 @@ public slots:
private:
void loadProfiles();
bool saveProfiles();
[[nodiscard]] bool removeWallpaperByAppID(const QString& appID);
private:

View File

@ -116,6 +116,13 @@ ProjectSettingsListModel* ScreenPlayWallpaper::getProjectSettingsListModel()
return &m_projectSettingsListModel;
}
void ScreenPlayWallpaper::setSDKConnection(const std::shared_ptr<SDKConnection> &connection)
{
m_connection = connection;
qInfo() << "App Wallpaper connected!";
//QObject::connect(m_connection.get(),&SDKConnection::readyRead,this,[](){});
}
void ScreenPlayWallpaper::replace(
const QString& absolutePath,
const QString& previewImage,

View File

@ -43,6 +43,7 @@
#include "globalvariables.h"
#include "projectsettingslistmodel.h"
#include "sdkconnection.h"
#include "sdkconnector.h"
namespace ScreenPlay {
@ -128,6 +129,8 @@ public:
ProjectSettingsListModel* getProjectSettingsListModel();
void setSDKConnection(const std::shared_ptr<SDKConnection>& connection);
void replace(const QString& absolutePath,
const QString& previewImage,
const QString& file,
@ -147,6 +150,7 @@ signals:
void profileJsonObjectChanged(QJsonObject profileJsonObject);
void volumeChanged(float volume);
void isLoopingChanged(bool isLooping);
void requestSave();
public slots:
void processExit(int exitCode, QProcess::ExitStatus exitStatus);
@ -242,6 +246,7 @@ private:
ProjectSettingsListModel m_projectSettingsListModel;
const std::shared_ptr<GlobalVariables>& m_globalVariables;
const std::shared_ptr<SDKConnector>& m_sdkConnector;
std::shared_ptr<SDKConnection> m_connection;
QVector<int> m_screenNumber;

View File

@ -47,6 +47,18 @@ ScreenPlayWidget::ScreenPlayWidget(
m_process.startDetached();
}
void ScreenPlayWidget::setSDKConnection(const std::shared_ptr<SDKConnection>& connection)
{
m_connection = connection;
qInfo() << "App widget connected!";
QObject::connect(m_connection.get(), &SDKConnection::jsonMessageReceived, this, [this](const QJsonObject obj) {
if (obj.value("messageType") == "positionUpdate") {
setPosition({ obj.value("positionX").toInt(0), obj.value("positionY").toInt(0) });
emit requestSave();
}
});
}
QJsonObject ScreenPlayWidget::getActiveSettingsJson()
{
QJsonObject obj;

View File

@ -37,6 +37,7 @@
#include <QCoreApplication>
#include <QDebug>
#include <QJsonObject>
#include <QLocalSocket>
#include <QObject>
#include <QPoint>
#include <QProcess>
@ -44,6 +45,7 @@
#include <memory>
#include "globalvariables.h"
#include "sdkconnection.h"
namespace ScreenPlay {
@ -91,6 +93,8 @@ public:
return m_type;
}
void setSDKConnection(const std::shared_ptr<SDKConnection>& connection);
public slots:
QJsonObject getActiveSettingsJson();
@ -145,6 +149,7 @@ signals:
void appIDChanged(QString appID);
void typeChanged(InstalledType::InstalledType type);
void absolutePathChanged(QString absolutePath);
void requestSave();
private:
QProcess m_process;
@ -155,5 +160,6 @@ private:
QPoint m_position;
InstalledType::InstalledType m_type;
QString m_absolutePath;
std::shared_ptr<SDKConnection> m_connection;
};
}

View File

@ -0,0 +1,91 @@
#include "sdkconnection.h"
ScreenPlay::SDKConnection::SDKConnection(QLocalSocket* socket, QObject* parent)
: QObject(parent)
{
m_socket = socket;
connect(m_socket, &QLocalSocket::readyRead, this, &SDKConnection::readyRead);
}
ScreenPlay::SDKConnection::~SDKConnection()
{
// We need to call this manually because
// sometimes it wont close the connection in
// the descructor
m_socket->disconnect();
m_socket->disconnectFromServer();
}
void ScreenPlay::SDKConnection::readyRead()
{
auto msg = QString(m_socket->readAll());
// The first message allways contains the appID
if (msg.startsWith("appID=")) {
QStringList args = msg.split(",");
//Only use the first 32 chars for the appID
QString appID = args.at(0);
m_appID = appID.remove("appID=");
bool typeFound = false;
for (const QString& type : GlobalVariables::getAvailableTypes()) {
if (msg.contains(type, Qt::CaseInsensitive)) {
m_type = type;
typeFound = true;
break;
}
}
if (!typeFound) {
qCritical() << "Wallpaper type not found. Expected: " << GlobalVariables::getAvailableTypes() << " got: " << msg;
}
emit appConnected(this);
} else if (msg.startsWith("command=")) {
msg.remove("command=");
if (msg == "requestRaise") {
qInfo() << "Another ScreenPlay instance reuqested this one to raise!";
emit requestRaise();
}
} else if (msg.startsWith("{") && msg.endsWith("}")) {
QJsonObject obj;
QJsonParseError err;
QJsonDocument doc = QJsonDocument::fromJson(QByteArray { msg.toUtf8() }, &err);
if (err.error != QJsonParseError::NoError)
return;
emit jsonMessageReceived(doc.object());
} else {
qInfo() << "### Message from: " << m_appID << ": " << msg;
}
}
void ScreenPlay::SDKConnection::close()
{
qInfo() << "Close " << m_type;
QJsonObject obj;
obj.insert("command", QJsonValue("quit"));
QByteArray command = QJsonDocument(obj).toJson();
m_socket->write(command);
m_socket->waitForBytesWritten();
if (m_socket->state() == QLocalSocket::ConnectedState) {
m_socket->disconnectFromServer();
m_socket->close();
qDebug() << "### Destroy APPID:\t " << m_appID << " State: " << m_socket->state();
}
if (m_type.contains("widget", Qt::CaseInsensitive)) {
emit requestDecreaseWidgetCount();
}
}

View File

@ -0,0 +1,142 @@
/****************************************************************************
**
** Copyright (C) 2020 Elias Steurer (Kelteseth)
** Contact: https://screen-play.app
**
** This file is part of ScreenPlay. ScreenPlay is licensed under a dual license in
** order to ensure its sustainability. When you contribute to ScreenPlay
** you accept that your work will be available under the two following licenses:
**
** $SCREENPLAY_BEGIN_LICENSE$
**
** #### Affero General Public License Usage (AGPLv3)
** Alternatively, this file may be used under the terms of the GNU Affero
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file "ScreenPlay License.md" included in the
** packaging of this App. Please review the following information to
** ensure the GNU Affero Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/agpl-3.0.en.html.
**
** #### Commercial License
** This code is owned by Elias Steurer. By changing/adding to the code you agree to the
** terms written in:
** * Legal/corporate_contributor_license_agreement.md - For corporate contributors
** * Legal/individual_contributor_license_agreement.md - For individual contributors
**
** #### Additional Limitations to the AGPLv3 and Commercial Lincese
** This License does not grant any rights in the trademarks,
** service marks, or logos.
**
**
** $SCREENPLAY_END_LICENSE$
**
****************************************************************************/
#pragma once
#include <QApplication>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include <QLocalServer>
#include <QLocalSocket>
#include <QObject>
#include <QString>
#include <QTimer>
#include <QVector>
#include <memory>
#include "globalvariables.h"
#include "util.h"
namespace ScreenPlay {
/*!
\class SDKConnection
\brief
*/
class SDKConnection : public QObject {
Q_OBJECT
Q_PROPERTY(QString appID READ appID WRITE setAppID NOTIFY appIDChanged)
Q_PROPERTY(QString type READ type WRITE setType NOTIFY typeChanged)
Q_PROPERTY(QVector<int> monitor READ monitor WRITE setMonitor NOTIFY monitorChanged)
public:
/*!
SDKConnection.
*/
explicit SDKConnection(QLocalSocket* socket, QObject* parent = nullptr);
~SDKConnection();
QString appID() const
{
return m_appID;
}
QLocalSocket* socket() const
{
return m_socket;
}
QVector<int> monitor() const
{
return m_monitor;
}
QString type() const
{
return m_type;
}
signals:
void requestCloseAt(int at);
void appIDChanged(QString appID);
void monitorChanged(QVector<int> monitor);
void typeChanged(QString type);
void requestDecreaseWidgetCount();
void requestRaise();
void appConnected(const SDKConnection* connection);
void jsonMessageReceived(const QJsonObject obj);
public slots:
void readyRead();
void close();
void setAppID(QString appID)
{
if (m_appID == appID)
return;
m_appID = appID;
emit appIDChanged(m_appID);
}
void setMonitor(QVector<int> monitor)
{
if (m_monitor == monitor)
return;
m_monitor = monitor;
emit monitorChanged(m_monitor);
}
void setType(QString type)
{
if (m_type == type)
return;
m_type = type;
emit typeChanged(m_type);
}
private:
QLocalSocket* m_socket { nullptr };
QString m_appID;
QVector<int> m_monitor;
QString m_type;
};
}

View File

@ -1,4 +1,5 @@
#include "sdkconnector.h"
#include "sdkconnection.h"
namespace ScreenPlay {
@ -64,6 +65,16 @@ void SDKConnector::newConnection()
// Because user can close widgets by pressing x the widgets must send us the event
QObject::connect(connection.get(), &SDKConnection::requestDecreaseWidgetCount, this, &SDKConnector::requestDecreaseWidgetCount);
QObject::connect(connection.get(), &SDKConnection::requestRaise, this, &SDKConnector::requestRaise);
// Only after we receive the first message with appID and type we can set the shared reference to the
// ScreenPlayWallpaper or ScreenPlayWidgets class
QObject::connect(connection.get(), &SDKConnection::appConnected, this, [this](const SDKConnection* connection) {
for (const auto& client : m_clients) {
if (client.get() == connection) {
emit appConnected(client);
return;
}
}
});
m_clients.append(connection);
}

View File

@ -47,6 +47,7 @@
#include <memory>
#include "globalvariables.h"
#include "util.h"
/*!
\class SDKConnector
@ -68,6 +69,7 @@ public:
signals:
void requestDecreaseWidgetCount();
void requestRaise();
void appConnected(const std::shared_ptr<SDKConnection>& connection);
public slots:
void newConnection();
@ -85,155 +87,4 @@ private:
bool isAnotherScreenPlayInstanceRunning();
};
class SDKConnection : public QObject {
Q_OBJECT
Q_PROPERTY(QString appID READ appID WRITE setAppID NOTIFY appIDChanged)
Q_PROPERTY(QString type READ type WRITE setType NOTIFY typeChanged)
Q_PROPERTY(QVector<int> monitor READ monitor WRITE setMonitor NOTIFY monitorChanged)
public:
/*!
SDKConnection.
*/
explicit SDKConnection(QLocalSocket* socket, QObject* parent = nullptr)
: QObject(parent)
{
m_socket = socket;
connect(m_socket, &QLocalSocket::readyRead, this, &SDKConnection::readyRead);
}
~SDKConnection()
{
// We need to call this manually because
// sometimes it wont close the connection in
// the descructor
m_socket->disconnect();
m_socket->disconnectFromServer();
}
QString appID() const
{
return m_appID;
}
QLocalSocket* socket() const
{
return m_socket;
}
QVector<int> monitor() const
{
return m_monitor;
}
QString type() const
{
return m_type;
}
signals:
void requestCloseAt(int at);
void appIDChanged(QString appID);
void monitorChanged(QVector<int> monitor);
void typeChanged(QString type);
void requestDecreaseWidgetCount();
void requestRaise();
public slots:
void readyRead()
{
auto msg = QString(m_socket->readAll());
// The first message allways contains the appID
if (msg.startsWith("appID=")) {
QStringList args = msg.split(",");
//Only use the first 32 chars for the appID
QString appID = args.at(0);
m_appID = appID.remove("appID=");
bool typeFound = false;
for (const QString& type : GlobalVariables::getAvailableTypes()) {
if (msg.contains(type, Qt::CaseInsensitive)) {
m_type = type;
typeFound = true;
break;
}
}
if (!typeFound) {
qCritical() << "Wallpaper type not found. Expected: " << GlobalVariables::getAvailableTypes() << " got: " << msg;
}
qInfo() << "###### " << m_type << " created:"
<< "\t AppID:" << m_appID;
} else if (msg.startsWith("command=")) {
msg.remove("command=");
if (msg == "requestRaise") {
qInfo() << "Another ScreenPlay instance reuqested this one to raise!";
emit requestRaise();
}
} else {
qInfo() << "### Message from: " << m_appID << ": " << msg;
}
}
void close()
{
qInfo() << "Close " << m_type;
QJsonObject obj;
obj.insert("command", QJsonValue("quit"));
QByteArray command = QJsonDocument(obj).toJson();
m_socket->write(command);
m_socket->waitForBytesWritten();
if (m_socket->state() == QLocalSocket::ConnectedState) {
m_socket->disconnectFromServer();
m_socket->close();
qDebug() << "### Destroy APPID:\t " << m_appID << " State: " << m_socket->state();
}
if (m_type.contains("widget", Qt::CaseInsensitive)) {
emit requestDecreaseWidgetCount();
}
}
void setAppID(QString appID)
{
if (m_appID == appID)
return;
m_appID = appID;
emit appIDChanged(m_appID);
}
void setMonitor(QVector<int> monitor)
{
if (m_monitor == monitor)
return;
m_monitor = monitor;
emit monitorChanged(m_monitor);
}
void setType(QString type)
{
if (m_type == type)
return;
m_type = type;
emit typeChanged(m_type);
}
private:
QLocalSocket* m_socket { nullptr };
QString m_appID;
QVector<int> m_monitor;
QString m_type;
};
}

View File

@ -78,6 +78,7 @@ public:
}
public slots:
void sendMessage(const QJsonObject& obj);
void connected();
void disconnected();
void readyRead();

View File

@ -49,6 +49,13 @@ ScreenPlaySDK::~ScreenPlaySDK()
m_socket.disconnectFromServer();
}
void ScreenPlaySDK::sendMessage(const QJsonObject& obj)
{
QJsonDocument doc(obj);
m_socket.write({ doc.toJson(QJsonDocument::Compact) });
m_socket.waitForBytesWritten();
}
void ScreenPlaySDK::connected()
{
QByteArray welcomeMessage = QString(m_appID + "," + m_type).toUtf8();

View File

@ -25,15 +25,29 @@ WidgetWindow::WidgetWindow(const QString& projectPath,
if (!availableTypes.contains(m_type)) {
QApplication::exit(-4);
}
auto sendPositionUpdate = [this](int arg) {
m_sdk->sendMessage({});
{
// We limit ourself to only update the position every 500ms!
auto sendPositionUpdate = [this]() {
m_positionMessageLimiter.stop();
if (!m_sdk->isConnected())
return;
QJsonObject obj;
obj.insert("messageType", "positionUpdate");
obj.insert("positionX", m_window.x());
obj.insert("positionY", m_window.y());
m_sdk->sendMessage(obj);
};
QObject::connect(&m_window, &QWindow::xChanged, this, sendPositionUpdate);
QObject::connect(&m_window, &QWindow::yChanged, this, sendPositionUpdate);
m_positionMessageLimiter.setInterval(500);
QObject::connect(&m_positionMessageLimiter, &QTimer::timeout, this, sendPositionUpdate);
QObject::connect(&m_window, &QWindow::xChanged, this, [this]() { m_positionMessageLimiter.start(); });
QObject::connect(&m_window, &QWindow::yChanged, this, [this]() { m_positionMessageLimiter.start(); });
}
Qt::WindowFlags flags = m_window.flags();
m_window.setWidth(300);
m_window.setHeight(300);
m_window.setFlags(flags | Qt::FramelessWindowHint | Qt::NoDropShadowWindowHint | Qt::BypassWindowManagerHint | Qt::SplashScreen);
m_window.setColor(Qt::transparent);
@ -68,7 +82,7 @@ WidgetWindow::WidgetWindow(const QString& projectPath,
// we can set it here once :)
m_window.setTextRenderType(QQuickWindow::TextRenderType::NativeTextRendering);
// m_window.setResizeMode(QQuickView::ResizeMode::SizeViewToRootObject);
m_window.setResizeMode(QQuickView::ResizeMode::SizeViewToRootObject);
m_window.setSource(QUrl("qrc:/Widget.qml"));
m_window.setPosition(m_position);
m_window.show();

View File

@ -183,4 +183,5 @@ private:
#endif
QPoint m_position;
std::unique_ptr<ScreenPlaySDK> m_sdk;
QTimer m_positionMessageLimiter;
};