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

WIP Refactor wallpaper timeline logic

TODO:
- Fix qcoro // QMetaObject::invokeMethod( requestSaveProfiles call
This commit is contained in:
Elias Steurer 2024-08-14 14:06:53 +02:00
parent 1f3ab94e26
commit d358c4f920
32 changed files with 601 additions and 223 deletions

View File

@ -10,9 +10,6 @@ include(GenerateCMakeVariableHeader)
set(SOURCES set(SOURCES
# cmake-format: sort # cmake-format: sort
src/wallpaperdata.cpp
src/wallpapertimelinesection.cpp
src/screenplaytimelinemanager.cpp
src/app.cpp src/app.cpp
src/applicationengine.cpp src/applicationengine.cpp
src/create.cpp src/create.cpp
@ -24,17 +21,17 @@ set(SOURCES
src/profilelistmodel.cpp src/profilelistmodel.cpp
src/projectsettingslistmodel.cpp src/projectsettingslistmodel.cpp
src/screenplaymanager.cpp src/screenplaymanager.cpp
src/screenplaytimelinemanager.cpp
src/screenplaywallpaper.cpp src/screenplaywallpaper.cpp
src/screenplaywidget.cpp src/screenplaywidget.cpp
src/sdkconnection.cpp src/sdkconnection.cpp
src/settings.cpp src/settings.cpp
src/wallpaperdata.cpp
src/wallpapertimelinesection.cpp
src/wizards.cpp) src/wizards.cpp)
set(HEADER set(HEADER
# cmake-format: sort # cmake-format: sort
inc/public/ScreenPlay/wallpaperdata.h
inc/public/ScreenPlay/wallpapertimelinesection.h
inc/public/ScreenPlay/screenplaytimelinemanager.h
inc/public/ScreenPlay/app.h inc/public/ScreenPlay/app.h
inc/public/ScreenPlay/applicationengine.h inc/public/ScreenPlay/applicationengine.h
inc/public/ScreenPlay/create.h inc/public/ScreenPlay/create.h
@ -48,24 +45,32 @@ set(HEADER
inc/public/ScreenPlay/profilelistmodel.h inc/public/ScreenPlay/profilelistmodel.h
inc/public/ScreenPlay/projectsettingslistmodel.h inc/public/ScreenPlay/projectsettingslistmodel.h
inc/public/ScreenPlay/screenplaymanager.h inc/public/ScreenPlay/screenplaymanager.h
inc/public/ScreenPlay/screenplaytimelinemanager.h
inc/public/ScreenPlay/screenplaywallpaper.h inc/public/ScreenPlay/screenplaywallpaper.h
inc/public/ScreenPlay/screenplaywidget.h inc/public/ScreenPlay/screenplaywidget.h
inc/public/ScreenPlay/sdkconnection.h inc/public/ScreenPlay/sdkconnection.h
inc/public/ScreenPlay/settings.h inc/public/ScreenPlay/settings.h
inc/public/ScreenPlay/wallpaperdata.h
inc/public/ScreenPlay/wallpapertimelinesection.h
inc/public/ScreenPlay/wizards.h) inc/public/ScreenPlay/wizards.h)
set(QML set(QML
# cmake-format: sort # cmake-format: sort
main.qml main.qml
qml/MainApp.qml qml/Community/CommunityNavItem.qml
qml/Components/TrayIcon.qml qml/Community/CommunityView.qml
qml/Community/XMLNewsfeed.qml
qml/Components/LineHandle.qml qml/Components/LineHandle.qml
qml/Components/LineIndicator.qml qml/Components/LineIndicator.qml
qml/Components/ScreenPlayProPopup.qml qml/Components/ScreenPlayProPopup.qml
qml/Components/Timeline.qml qml/Components/Timeline.qml
qml/Community/CommunityNavItem.qml qml/Components/TrayIcon.qml
qml/Community/CommunityView.qml qml/ContentSettings/ContentSettingsView.qml
qml/Community/XMLNewsfeed.qml qml/ContentSettings/DefaultVideoControls.qml
qml/ContentSettings/MonitorSelection.qml
qml/ContentSettings/MonitorSelectionItem.qml
qml/ContentSettings/MonitorsProjectSettingItem.qml
qml/ContentSettings/SaveNotification.qml
qml/Create/CreateSidebar.qml qml/Create/CreateSidebar.qml
qml/Create/CreateView.qml qml/Create/CreateView.qml
qml/Create/StartInfo.qml qml/Create/StartInfo.qml
@ -84,18 +89,13 @@ set(QML
qml/Create/Wizards/QMLWidget.qml qml/Create/Wizards/QMLWidget.qml
qml/Create/Wizards/WebsiteWallpaper.qml qml/Create/Wizards/WebsiteWallpaper.qml
qml/Create/Wizards/WizardPage.qml qml/Create/Wizards/WizardPage.qml
qml/Installed/InstalledDrawer.qml
qml/Installed/InstalledItem.qml
qml/Installed/InstalledItemImage.qml
qml/Installed/InstalledNavigation.qml qml/Installed/InstalledNavigation.qml
qml/Installed/InstalledView.qml qml/Installed/InstalledView.qml
qml/Installed/InstalledWelcomeScreen.qml qml/Installed/InstalledWelcomeScreen.qml
qml/Installed/ScreenPlayItem.qml qml/MainApp.qml
qml/Installed/ScreenPlayItemImage.qml
qml/Installed/InstalledDrawer.qml
qml/ContentSettings/DefaultVideoControls.qml
qml/ContentSettings/MonitorSelection.qml
qml/ContentSettings/MonitorSelectionItem.qml
qml/ContentSettings/MonitorsProjectSettingItem.qml
qml/ContentSettings/ContentSettingsView.qml
qml/ContentSettings/SaveNotification.qml
qml/Navigation/ExitPopup.qml qml/Navigation/ExitPopup.qml
qml/Navigation/Navigation.qml qml/Navigation/Navigation.qml
qml/Settings/SettingBool.qml qml/Settings/SettingBool.qml
@ -135,9 +135,9 @@ set(RESOURCES
assets/icons/brand_twitch.svg assets/icons/brand_twitch.svg
assets/icons/brand_twitter.svg assets/icons/brand_twitter.svg
assets/icons/exclamation-triangle-solid.svg assets/icons/exclamation-triangle-solid.svg
assets/icons/font-awsome/lock-solid.svg
assets/icons/font-awsome/close.svg assets/icons/font-awsome/close.svg
assets/icons/font-awsome/frown-o.svg assets/icons/font-awsome/frown-o.svg
assets/icons/font-awsome/lock-solid.svg
assets/icons/font-awsome/patreon-brands.svg assets/icons/font-awsome/patreon-brands.svg
assets/icons/font-awsome/rotate-right-solid.svg assets/icons/font-awsome/rotate-right-solid.svg
assets/icons/icon_arrow_left.svg assets/icons/icon_arrow_left.svg
@ -194,8 +194,6 @@ set(RESOURCES
assets/icons/item_banner_new.svg assets/icons/item_banner_new.svg
assets/icons/monitor_setup.svg assets/icons/monitor_setup.svg
assets/icons/steam_default_avatar.png assets/icons/steam_default_avatar.png
assets/images/rocket_3d.png
assets/images/pro_version.png
assets/images/Intro.png assets/images/Intro.png
assets/images/Intro_PC.png assets/images/Intro_PC.png
assets/images/Intro_shine.png assets/images/Intro_shine.png
@ -204,6 +202,8 @@ set(RESOURCES
assets/images/missingPreview.png assets/images/missingPreview.png
assets/images/noisy-texture-3.png assets/images/noisy-texture-3.png
assets/images/noisy-texture.png assets/images/noisy-texture.png
assets/images/pro_version.png
assets/images/rocket_3d.png
assets/images/scale_window_indicator.png assets/images/scale_window_indicator.png
assets/images/steam_offline.png assets/images/steam_offline.png
assets/images/trayIcon_osx.png assets/images/trayIcon_osx.png

View File

@ -14,6 +14,7 @@
#include "ScreenPlay/wallpapertimelinesection.h" #include "ScreenPlay/wallpapertimelinesection.h"
#include "ScreenPlayUtil/contenttypes.h" #include "ScreenPlayUtil/contenttypes.h"
#include "ScreenPlayUtil/globalenums.h"
namespace ScreenPlay { namespace ScreenPlay {
@ -31,6 +32,7 @@ struct Monitor {
QRect m_geometry; QRect m_geometry;
QString m_wallpaperPreviewImage; QString m_wallpaperPreviewImage;
QString m_appID; QString m_appID;
ScreenPlayEnums::AppState m_appState = ScreenPlayEnums::AppState::Inactive;
ContentTypes::InstalledType m_installedType = ContentTypes::InstalledType::Unknown; ContentTypes::InstalledType m_installedType = ContentTypes::InstalledType::Unknown;
}; };
@ -45,6 +47,7 @@ public:
enum class MonitorRole { enum class MonitorRole {
AppID = Qt::UserRole, AppID = Qt::UserRole,
AppState,
Index, Index,
Geometry, Geometry,
PreviewImage, PreviewImage,

View File

@ -23,8 +23,9 @@ class ScreenPlayManager : public QObject {
QML_ELEMENT QML_ELEMENT
QML_UNCREATABLE("") QML_UNCREATABLE("")
Q_PROPERTY(int activeWallpaperCounter READ activeWallpaperCounter WRITE setActiveWallpaperCounter NOTIFY activeWallpaperCounterChanged) Q_PROPERTY(int activeWallpaperCounter READ activeWallpaperCounter WRITE setActiveWallpaperCounter NOTIFY activeWallpaperCounterChanged FINAL)
Q_PROPERTY(int activeWidgetsCounter READ activeWidgetsCounter WRITE setActiveWidgetsCounter NOTIFY activeWidgetsCounterChanged) Q_PROPERTY(int activeWidgetsCounter READ activeWidgetsCounter WRITE setActiveWidgetsCounter NOTIFY activeWidgetsCounterChanged FINAL)
Q_PROPERTY(int selectedTimelineIndex READ selectedTimelineIndex WRITE setSelectedTimelineIndex NOTIFY selectedTimelineIndexChanged FINAL)
public: public:
explicit ScreenPlayManager(QObject* parent = nullptr); explicit ScreenPlayManager(QObject* parent = nullptr);
@ -37,7 +38,6 @@ public:
Q_INVOKABLE QCoro::QmlTask removeAllRunningWallpapers(bool saveToProfile = false); Q_INVOKABLE QCoro::QmlTask removeAllRunningWallpapers(bool saveToProfile = false);
Q_INVOKABLE bool removeAllRunningWidgets(bool saveToProfile = false); Q_INVOKABLE bool removeAllRunningWidgets(bool saveToProfile = false);
Q_INVOKABLE QCoro::QmlTask removeWallpaperAt(const int timelineIndex, const QString timelineIdentifier, const int monitorIndex); Q_INVOKABLE QCoro::QmlTask removeWallpaperAt(const int timelineIndex, const QString timelineIdentifier, const int monitorIndex);
Q_INVOKABLE ScreenPlayWallpaper* getWallpaperByAppID(const QString& appID); Q_INVOKABLE ScreenPlayWallpaper* getWallpaperByAppID(const QString& appID);
Q_INVOKABLE bool moveTimelineAt( Q_INVOKABLE bool moveTimelineAt(
@ -49,9 +49,10 @@ public:
const int index, const int index,
const float reltiaveLinePosition, const float reltiaveLinePosition,
QString identifier); QString identifier);
Q_INVOKABLE QCoro::QmlTask removeAllTimlineSections();
Q_INVOKABLE bool removeTimelineAt(const int index); Q_INVOKABLE bool removeTimelineAt(const int index);
Q_INVOKABLE QJsonArray timelineSections(); Q_INVOKABLE QJsonArray timelineSections();
Q_INVOKABLE QCoro::QmlTask removeAllTimlineSections();
Q_INVOKABLE QCoro::QmlTask setWallpaperAtTimelineIndex( Q_INVOKABLE QCoro::QmlTask setWallpaperAtTimelineIndex(
const ScreenPlay::ContentTypes::InstalledType type, const ScreenPlay::ContentTypes::InstalledType type,
const QString& absolutePath, const QString& absolutePath,
@ -71,28 +72,31 @@ public:
const QJsonObject& properties, const QJsonObject& properties,
const bool saveToProfilesConfigFile); const bool saveToProfilesConfigFile);
Q_INVOKABLE void setSelectedTimelineIndex(const int selectedTimelineIndex);
Q_INVOKABLE bool requestProjectSettingsAtMonitorIndex(const int index); Q_INVOKABLE bool requestProjectSettingsAtMonitorIndex(const int index);
Q_INVOKABLE bool setWallpaperValueAtMonitorIndex(const int index, const QString& key, const QString& value); Q_INVOKABLE bool setWallpaperValueAtMonitorIndex(const int index, const QString& key, const QString& value);
Q_INVOKABLE bool setWallpaperFillModeAtMonitorIndex(const int index, const int fillmode); Q_INVOKABLE bool setWallpaperFillModeAtMonitorIndex(const int index, const int fillmode);
Q_INVOKABLE bool setAllWallpaperValue(const QString& key, const QString& value); Q_INVOKABLE bool setAllWallpaperValue(const QString& key, const QString& value);
Q_INVOKABLE bool setWallpaperValue(const QString& appID, const QString& key, const QString& value); Q_INVOKABLE bool setWallpaperValue(const QString& appID, const QString& key, const QString& value);
Q_INVOKABLE int activeTimelineIndex(); Q_INVOKABLE int activeTimelineIndex();
Q_INVOKABLE void requestSaveProfiles();
int activeWallpaperCounter() const { return m_activeWallpaperCounter; } int activeWallpaperCounter() const { return m_activeWallpaperCounter; }
int activeWidgetsCounter() const { return m_activeWidgetsCounter; } int activeWidgetsCounter() const { return m_activeWidgetsCounter; }
int selectedTimelineIndex() const { return m_selectedTimelineIndex; }
public slots:
void setSelectedTimelineIndex(int selectedTimelineIndex);
signals: signals:
void activeWallpaperCounterChanged(int activeWallpaperCounter); void activeWallpaperCounterChanged(int activeWallpaperCounter);
void activeWidgetsCounterChanged(int activeWidgetsCounter); void activeWidgetsCounterChanged(int activeWidgetsCounter);
void monitorConfigurationChanged(); void monitorConfigurationChanged();
void projectSettingsListModelResult(ScreenPlay::ProjectSettingsListModel* li = nullptr); void projectSettingsListModelResult(ScreenPlay::ProjectSettingsListModel* li = nullptr);
void requestSaveProfiles();
void requestRaise(); void requestRaise();
void profilesSaved(); void profilesSaved();
void printQmlTimeline(); void printQmlTimeline();
void displayErrorPopup(const QString& msg); void displayErrorPopup(const QString& msg);
void selectedTimelineIndexChanged(int selectedTimelineIndex);
private slots: private slots:
bool saveProfiles(); bool saveProfiles();
@ -102,12 +106,11 @@ private slots:
private: private:
bool loadProfiles(); bool loadProfiles();
bool checkIsAnotherScreenPlayInstanceRunning(); bool checkIsAnotherScreenPlayInstanceRunning();
bool removeWallpaper(const QString& appID);
bool removeWidget(const QString& appID); bool removeWidget(const QString& appID);
bool loadWidgetConfig(const QJsonObject& widget); bool loadWidgetConfig(const QJsonObject& widget);
private:
std::shared_ptr<GlobalVariables> m_globalVariables; std::shared_ptr<GlobalVariables> m_globalVariables;
std::shared_ptr<MonitorListModel> m_monitorListModel; std::shared_ptr<MonitorListModel> m_monitorListModel;
std::shared_ptr<Settings> m_settings; std::shared_ptr<Settings> m_settings;
@ -116,14 +119,12 @@ private:
std::vector<std::unique_ptr<SDKConnection>> m_unconnectedClients; std::vector<std::unique_ptr<SDKConnection>> m_unconnectedClients;
ScreenPlayTimelineManager m_screenPlayTimelineManager; ScreenPlayTimelineManager m_screenPlayTimelineManager;
int m_activeWallpaperCounter { 0 };
int m_activeWidgetsCounter { 0 };
QTimer m_saveLimiter; QTimer m_saveLimiter;
Util m_util; Util m_util;
int m_activeWallpaperCounter { 0 };
int m_activeWidgetsCounter { 0 };
int m_selectedTimelineIndex { 0 };
const quint16 m_webSocketPort = 16395; const quint16 m_webSocketPort = 16395;
}; };
} }

View File

@ -13,6 +13,7 @@ namespace ScreenPlay {
class ScreenPlayTimelineManager : public QObject { class ScreenPlayTimelineManager : public QObject {
Q_OBJECT Q_OBJECT
Q_PROPERTY(int selectedTimelineIndex READ selectedTimelineIndex WRITE setSelectedTimelineIndex NOTIFY selectedTimelineIndexChanged FINAL)
public: public:
explicit ScreenPlayTimelineManager(QObject* parent = nullptr); explicit ScreenPlayTimelineManager(QObject* parent = nullptr);
@ -45,6 +46,11 @@ public:
void setGlobalVariables(const std::shared_ptr<GlobalVariables>& globalVariables); void setGlobalVariables(const std::shared_ptr<GlobalVariables>& globalVariables);
void setSettings(const std::shared_ptr<Settings>& settings); void setSettings(const std::shared_ptr<Settings>& settings);
void setMonitorListModel(const std::shared_ptr<MonitorListModel>& monitorListModel); void setMonitorListModel(const std::shared_ptr<MonitorListModel>& monitorListModel);
int selectedTimelineIndex() const;
void setSelectedTimelineIndex(int selectedTimelineIndex);
public slots:
void updateMonitorListModelData(const int selectedTimelineIndex); void updateMonitorListModelData(const int selectedTimelineIndex);
private slots: private slots:
@ -53,9 +59,12 @@ private slots:
signals: signals:
void requestSaveProfiles(); void requestSaveProfiles();
void activeWallpaperCountChanged(const int count); void activeWallpaperCountChanged(const int count);
void selectedTimelineIndexChanged(int selectedTimelineIndex);
private: private:
std::optional<std::shared_ptr<WallpaperTimelineSection>> wallpaperSection(const int timelineIndex, const QString timelineIdentifier); std::optional<std::shared_ptr<WallpaperTimelineSection>> wallpaperSection(
const int timelineIndex,
const QString timelineIdentifier);
private: private:
QVector<std::shared_ptr<WallpaperTimelineSection>> m_wallpaperTimelineSectionsList; QVector<std::shared_ptr<WallpaperTimelineSection>> m_wallpaperTimelineSectionsList;
@ -66,5 +75,6 @@ private:
QTimer m_contentTimer; QTimer m_contentTimer;
std::shared_ptr<GlobalVariables> m_globalVariables; std::shared_ptr<GlobalVariables> m_globalVariables;
std::shared_ptr<Settings> m_settings; std::shared_ptr<Settings> m_settings;
int m_selectedTimelineIndex { 0 };
}; };
} }

View File

@ -14,18 +14,18 @@
#include "ScreenPlay/projectsettingslistmodel.h" #include "ScreenPlay/projectsettingslistmodel.h"
#include "ScreenPlay/sdkconnection.h" #include "ScreenPlay/sdkconnection.h"
#include "ScreenPlay/settings.h" #include "ScreenPlay/settings.h"
#include "ScreenPlayUtil/processmanager.h"
#include "ScreenPlay/wallpaperdata.h" #include "ScreenPlay/wallpaperdata.h"
#include "ScreenPlay/wallpapertimelinesection.h" #include "ScreenPlay/wallpapertimelinesection.h"
#include "ScreenPlayUtil/globalenums.h"
#include "ScreenPlayUtil/processmanager.h"
namespace ScreenPlay { namespace ScreenPlay {
class ScreenPlayWallpaper : public QObject { class ScreenPlayWallpaper : public QObject {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
QML_UNCREATABLE("") QML_UNCREATABLE("")
Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
Q_PROPERTY(bool isConnected READ isConnected WRITE setIsConnected NOTIFY isConnectedChanged) Q_PROPERTY(bool isConnected READ isConnected WRITE setIsConnected NOTIFY isConnectedChanged)
Q_PROPERTY(QVector<int> monitors READ monitors WRITE setMonitors NOTIFY monitorsChanged) Q_PROPERTY(QVector<int> monitors READ monitors WRITE setMonitors NOTIFY monitorsChanged)
@ -36,9 +36,10 @@ class ScreenPlayWallpaper : public QObject {
Q_PROPERTY(QString absolutePath READ absolutePath WRITE setAbsolutePath NOTIFY absolutePathChanged) Q_PROPERTY(QString absolutePath READ absolutePath WRITE setAbsolutePath NOTIFY absolutePathChanged)
Q_PROPERTY(QString previewImage READ previewImage WRITE setPreviewImage NOTIFY previewImageChanged) Q_PROPERTY(QString previewImage READ previewImage WRITE setPreviewImage NOTIFY previewImageChanged)
Q_PROPERTY(QString appID READ appID WRITE setAppID NOTIFY appIDChanged) Q_PROPERTY(QString appID READ appID WRITE setAppID NOTIFY appIDChanged)
Q_PROPERTY(Video::FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged)
Q_PROPERTY(ContentTypes::InstalledType type READ type WRITE setType NOTIFY typeChanged)
Q_PROPERTY(qint64 processID READ processID WRITE setProcessID NOTIFY processIDChanged FINAL) Q_PROPERTY(qint64 processID READ processID WRITE setProcessID NOTIFY processIDChanged FINAL)
Q_PROPERTY(ScreenPlay::Video::FillMode fillMode READ fillMode WRITE setFillMode NOTIFY fillModeChanged)
Q_PROPERTY(ScreenPlay::ContentTypes::InstalledType type READ type WRITE setType NOTIFY typeChanged)
Q_PROPERTY(ScreenPlay::ScreenPlayEnums::AppState state READ state WRITE setState NOTIFY stateChanged FINAL)
public: public:
explicit ScreenPlayWallpaper( explicit ScreenPlayWallpaper(
@ -74,6 +75,9 @@ public:
const WallpaperData& wallpaperData(); const WallpaperData& wallpaperData();
ScreenPlay::ScreenPlayEnums::AppState state() const;
void setState(ScreenPlay::ScreenPlayEnums::AppState state);
signals: signals:
void monitorsChanged(QVector<int> monitors); void monitorsChanged(QVector<int> monitors);
void previewImageChanged(QString previewImage); void previewImageChanged(QString previewImage);
@ -93,6 +97,8 @@ signals:
void requestClose(const QString& appID); void requestClose(const QString& appID);
void error(const QString& msg); void error(const QString& msg);
void stateChanged(ScreenPlay::ScreenPlayEnums::AppState state);
public slots: public slots:
void close(); void close();
void processExit(int exitCode, QProcess::ExitStatus exitStatus); void processExit(int exitCode, QProcess::ExitStatus exitStatus);
@ -126,7 +132,7 @@ public slots:
emit appIDChanged(m_appID); emit appIDChanged(m_appID);
} }
void setType(ContentTypes::InstalledType type) void setType(ScreenPlay::ContentTypes::InstalledType type)
{ {
if (m_wallpaperData.type == type) if (m_wallpaperData.type == type)
return; return;
@ -144,7 +150,7 @@ public slots:
emit fileChanged(m_wallpaperData.file); emit fileChanged(m_wallpaperData.file);
} }
void setFillMode(Video::FillMode fillMode) void setFillMode(ScreenPlay::Video::FillMode fillMode)
{ {
if (m_wallpaperData.fillMode == fillMode) if (m_wallpaperData.fillMode == fillMode)
return; return;
@ -218,6 +224,7 @@ private:
QJsonObject m_projectJson; QJsonObject m_projectJson;
QProcess m_process; QProcess m_process;
QString m_appID; QString m_appID;
ScreenPlay::ScreenPlayEnums::AppState m_state = ScreenPlay::ScreenPlayEnums::AppState::Inactive;
WallpaperData m_wallpaperData; WallpaperData m_wallpaperData;

View File

@ -23,6 +23,7 @@ class WallpaperTimelineSection : public QObject {
QML_UNCREATABLE("") QML_UNCREATABLE("")
Q_CLASSINFO("RegisterEnumClassesUnscoped", "false") Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
public: public:
// TODO: replace with wallpaper state?
enum class State { enum class State {
Inactive, Inactive,
Starting, Starting,
@ -46,6 +47,11 @@ public:
std::shared_ptr<GlobalVariables> globalVariables; std::shared_ptr<GlobalVariables> globalVariables;
std::shared_ptr<Settings> settings; std::shared_ptr<Settings> settings;
signals:
void requestSaveProfiles();
void requestUpdateMonitorListModel();
void activeWallpaperCountChanged(const int count);
public: public:
// Check if currentTime falls within the timeline section // Check if currentTime falls within the timeline section
bool containsTime(const QTime& time) const; bool containsTime(const QTime& time) const;
@ -58,9 +64,5 @@ private slots:
private: private:
std::optional<std::shared_ptr<ScreenPlayWallpaper>> wallpaperByMonitorIndex(const int index); std::optional<std::shared_ptr<ScreenPlayWallpaper>> wallpaperByMonitorIndex(const int index);
signals:
void requestSaveProfiles();
void activeWallpaperCountChanged(const int count);
}; };
} }

View File

@ -1,5 +1,6 @@
import QtQuick import QtQuick
import QtQuick.Controls import QtQuick.Controls
import ScreenPlayUtil as Util
Rectangle { Rectangle {
id: root id: root
@ -26,9 +27,8 @@ Rectangle {
} }
} }
Rectangle { Util.RainbowGradient {
opacity: root.isActive ? 1 : 0 opacity: root.isActive ? 1 : 0
color: "gold"
height: root.height height: root.height
anchors { anchors {
right: parent.right right: parent.right
@ -42,27 +42,21 @@ Rectangle {
} }
} }
Rectangle {
visible: root.selected
color: "gold"
height: 3
anchors {
right: parent.right
left: parent.left
top: parent.bottom
}
}
Rectangle { Rectangle {
id: indicatorLineVertical id: indicatorLineVertical
width: 5 width: 5
height: 30 height: root.selected ? 40 : 30
color: root.selected ? "gold" : parent.color color: root.selected ? "gold" : parent.color
anchors { anchors {
horizontalCenter: parent.horizontalCenter horizontalCenter: parent.horizontalCenter
top: parent.bottom top: parent.bottom
topMargin: 0 topMargin: 0
} }
Behavior on height {
NumberAnimation {
duration: 200
}
}
Behavior on color { Behavior on color {
@ -94,6 +88,7 @@ Rectangle {
radius: 5 radius: 5
clip: true clip: true
color: Qt.darker(monitorBackground.color) color: Qt.darker(monitorBackground.color)
Image { Image {
id: imgWallpaper id: imgWallpaper
opacity: imgWallpaper.status === Image.Ready ? 1 : 0 opacity: imgWallpaper.status === Image.Ready ? 1 : 0
@ -115,6 +110,7 @@ Rectangle {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
root.lineSelected(root.index); root.lineSelected(root.index);
} }

View File

@ -5,6 +5,7 @@ import QtQuick.Controls
import QtQuick.Layouts import QtQuick.Layouts
import ScreenPlayApp import ScreenPlayApp
import ScreenPlayUtil import ScreenPlayUtil
import "../../../ScreenPlayUtil/qml/InstantPopup.js" as InstantPopup
Control { Control {
id: root id: root
@ -121,7 +122,7 @@ Control {
if (timelineSection.wallpaperData.length === 0) if (timelineSection.wallpaperData.length === 0)
continue; continue;
let firstWallpaper = timelineSection.wallpaperData[0]; let firstWallpaper = timelineSection.wallpaperData[0];
lineIndicator.wallpaperPreviewImage = Qt.resolvedUrl("file:///" + firstWallpaper.absolutePath + "/" + firstWallpaper.previewImage); lineIndicator.wallpaperPreviewImage = "file:///" + firstWallpaper.absolutePath + "/" + firstWallpaper.previewImage;
} }
} }
@ -509,7 +510,7 @@ Control {
btnReset.resetting = true; btnReset.resetting = true;
App.screenPlayManager.removeAllRunningWallpapers().then(result => { App.screenPlayManager.removeAllRunningWallpapers().then(result => {
if (!result.success) { if (!result.success) {
console.error("removeAllTimlineSections failed"); InstantPopup.openErrorPopup(timeline, result.message);
btnReset.resetting = false; btnReset.resetting = false;
return; return;
} }
@ -523,7 +524,9 @@ Control {
const position = 1.0; const position = 1.0;
const identifier = App.util.generateRandomString(4); const identifier = App.util.generateRandomString(4);
const sectionObject = timeline.addSection(identifier, position); const sectionObject = timeline.addSection(identifier, position);
App.screenPlayManager.addTimelineAt(sectionObject.index, sectionObject.relativeLinePosition, sectionObject.identifier); const success = App.screenPlayManager.addTimelineAt(sectionObject.index, sectionObject.relativeLinePosition, sectionObject.identifier);
if (!success)
InstantPopup.openErrorPopup(timeline, qsTr("Unable to add Timeline"));
btnReset.resetting = false; btnReset.resetting = false;
}); });
}); });

View File

@ -6,7 +6,7 @@ import QtQuick.Layouts
import QtQuick.Controls.Material.impl import QtQuick.Controls.Material.impl
import ScreenPlayApp import ScreenPlayApp
import ScreenPlayUtil as Util import ScreenPlayUtil as Util
import "../../../ScreenPlayUtil/qml/InstantPopup.js" as InstantPopup
import "../Components" import "../Components"
Util.Popup { Util.Popup {
@ -149,7 +149,12 @@ Util.Popup {
monitorSelection.enabled = false; monitorSelection.enabled = false;
App.screenPlayManager.removeWallpaperAt(index, selectedTimeline.identifier, selectedTimeline.index).then(result => { App.screenPlayManager.removeWallpaperAt(index, selectedTimeline.identifier, selectedTimeline.index).then(result => {
monitorSelection.enabled = true; monitorSelection.enabled = true;
if (!result.success) {} else {} if (result.success) {
App.screenPlayManager.requestSaveProfiles();
} else {
if (!success)
InstantPopup.openErrorPopup(this, result);
}
}); });
} }
@ -169,7 +174,7 @@ Util.Popup {
} }
} }
ColumnLayout { RowLayout {
spacing: 5 spacing: 5
anchors { anchors {
@ -179,23 +184,10 @@ Util.Popup {
margins: 20 margins: 20
} }
Button {
id: btnRemoveSelectedWallpaper
Material.background: Material.accent
highlighted: true
text: qsTr("Remove selected")
font.family: App.settings.font
enabled: monitorSelection.activeMonitors.length == 1 && App.screenPlayManager.activeWallpaperCounter > 0
onClicked: {
if (!App.screenPlayManager.removeWallpaperAt(monitorSelection.activeMonitors[0]))
print("Unable to close singel wallpaper");
}
}
Button { Button {
id: btnRemoveAllWallpaper id: btnRemoveAllWallpaper
text: qsTr("Remove all ") + App.screenPlayManager.activeWallpaperCounter + " " + qsTr("Wallpapers") text: qsTr("Remove all running") + App.screenPlayManager.activeWallpaperCounter + " " + qsTr("Wallpapers")
Material.background: Material.accent Material.background: Material.accent
highlighted: true highlighted: true
font.family: App.settings.font font.family: App.settings.font
@ -209,7 +201,7 @@ Util.Popup {
Button { Button {
id: btnRemoveAllWidgets id: btnRemoveAllWidgets
text: qsTr("Remove all ") + App.screenPlayManager.activeWidgetsCounter + " " + qsTr("Widgets") text: qsTr("Remove all running") + App.screenPlayManager.activeWidgetsCounter + " " + qsTr("Widgets")
Material.background: Material.accent Material.background: Material.accent
Material.foreground: Material.primaryTextColor Material.foreground: Material.primaryTextColor
highlighted: true highlighted: true

View File

@ -173,6 +173,7 @@ Rectangle {
index: m_index index: m_index
previewImage: m_previewImage previewImage: m_previewImage
installedType: m_installedType installedType: m_installedType
appState: m_appState
monitorWithoutContentSelectable: root.monitorWithoutContentSelectable monitorWithoutContentSelectable: root.monitorWithoutContentSelectable
onMonitorSelected: function (index) { onMonitorSelected: function (index) {
root.selectMonitorAt(index); root.selectMonitorAt(index);

View File

@ -9,6 +9,7 @@ Item {
property string previewImage property string previewImage
property string appID property string appID
property var installedType: ContentTypes.InstalledType.QMLWallpaper property var installedType: ContentTypes.InstalledType.QMLWallpaper
property var appState: ScreenPlayEnums.AppState.Inactive
property bool monitorWithoutContentSelectable: true property bool monitorWithoutContentSelectable: true
property bool hasContent: appID !== "" property bool hasContent: appID !== ""
property int fontSize: 10 property int fontSize: 10
@ -85,6 +86,25 @@ Item {
asynchronous: true asynchronous: true
fillMode: Image.PreserveAspectCrop fillMode: Image.PreserveAspectCrop
} }
Text {
anchors.fill: parent
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: {
switch (root.appState) {
case ScreenPlayEnums.AppState.Inactive:
return qsTr("Inactive");
case ScreenPlayEnums.AppState.Starting:
return qsTr("Starting");
case ScreenPlayEnums.AppState.Closing:
return qsTr("Closing");
case ScreenPlayEnums.AppState.Active:
return qsTr("Active");
default:
console.error("Invalid state");
}
}
}
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent

View File

@ -7,6 +7,7 @@ import QtQuick.Controls.Material
import QtQuick.Controls.Material.impl import QtQuick.Controls.Material.impl
import ScreenPlayApp import ScreenPlayApp
import ScreenPlayUtil import ScreenPlayUtil
import "../../../ScreenPlayUtil/qml/InstantPopup.js" as InstantPopup
import "../ContentSettings" import "../ContentSettings"
import "../Components" import "../Components"
@ -135,7 +136,7 @@ Drawer {
onRequestRemoveWallpaper: monitorIndex => { onRequestRemoveWallpaper: monitorIndex => {
const selectedTimeline = timeline.getSelectedTimeline(); const selectedTimeline = timeline.getSelectedTimeline();
if (selectedTimeline === undefined) { if (selectedTimeline === undefined) {
console.error("No active timeline to remove wallpaper ", index); InstantPopup.openErrorPopup(timeline, qsTr("No active timeline to remove wallpaper"));
return; return;
} }
monitorSelection.enabled = false; monitorSelection.enabled = false;
@ -144,6 +145,9 @@ Drawer {
if (result.success) { if (result.success) {
// Reset to update the wallpaper preview image // Reset to update the wallpaper preview image
timeline.reset(); timeline.reset();
App.screenPlayManager.requestSaveProfiles();
} else {
InstantPopup.openErrorPopup(timeline, result.message);
} }
}); });
} }
@ -235,16 +239,6 @@ Drawer {
} }
} }
Dialog {
id: dialog
standardButtons: Dialog.Ok
title: qsTr("Export Godot project")
property alias message: messageText.text
Text {
id: messageText
}
}
Button { Button {
id: btnLaunchContent id: btnLaunchContent
Layout.fillWidth: true Layout.fillWidth: true
@ -256,12 +250,14 @@ Drawer {
icon.color: "white" icon.color: "white"
font.pointSize: 12 font.pointSize: 12
onClicked: { onClicked: {
btnLaunchContent.enabled = false;
const item = App.installedListModel.get(root.contentFolderName); const item = App.installedListModel.get(root.contentFolderName);
const absoluteStoragePath = item.m_absoluteStoragePath; const absoluteStoragePath = item.m_absoluteStoragePath;
const previewImage = item.m_preview; const previewImage = item.m_preview;
if (App.util.isWallpaper(root.type)) { if (App.util.isWallpaper(root.type)) {
if (type === ContentTypes.InstalledType.GodotWallpaper) { if (type === ContentTypes.InstalledType.GodotWallpaper) {
if (App.globalVariables.isBasicVersion()) { if (App.globalVariables.isBasicVersion()) {
InstantPopup.openErrorPopup(timeline, qsTr("You are not allowed to do that!"));
installedDrawerWrapper.state = "inactive"; installedDrawerWrapper.state = "inactive";
return; return;
} }
@ -270,14 +266,19 @@ Drawer {
if (type === ContentTypes.InstalledType.GodotWallpaper) { if (type === ContentTypes.InstalledType.GodotWallpaper) {
App.util.exportGodotProject(absoluteStoragePath, App.globalVariables.godotEditorExecutablePath).then(result => { App.util.exportGodotProject(absoluteStoragePath, App.globalVariables.godotEditorExecutablePath).then(result => {
if (!result.success) { if (!result.success) {
dialog.title = ("Error exporting Godot"); btnLaunchContent.enabled = true;
dialog.message = result.message; InstantPopup.openErrorPopup(timeline, result.message);
dialog.open();
} else { } else {
const file = item.m_file; const file = item.m_file;
let volume = 1; let volume = 1;
const selectedTimeline = timeline.getSelectedTimeline(); const selectedTimeline = timeline.getSelectedTimeline();
let success = App.screenPlayManager.setWallpaperAtTimelineIndex(root.type, absoluteStoragePath, previewImage, file, activeMonitors, selectedTimeline.index, selectedTimeline.identifier, true); App.screenPlayManager.setWallpaperAtTimelineIndex(root.type, absoluteStoragePath, previewImage, file, activeMonitors, selectedTimeline.index, selectedTimeline.identifier, true).then(result => {
btnLaunchContent.enabled = true;
if (!result.success) {
InstantPopup.openErrorPopup(timeline, result.message);
return;
}
});
} }
}); });
root.close(); root.close();
@ -285,15 +286,17 @@ Drawer {
} }
const selectedTimeline = timeline.getSelectedTimeline(); const selectedTimeline = timeline.getSelectedTimeline();
const file = item.m_file; const file = item.m_file;
let success = App.screenPlayManager.setWallpaperAtTimelineIndex(root.type, absoluteStoragePath, previewImage, file, activeMonitors, selectedTimeline.index, selectedTimeline.identifier, true).then(result => { App.screenPlayManager.setWallpaperAtTimelineIndex(root.type, absoluteStoragePath, previewImage, file, activeMonitors, selectedTimeline.index, selectedTimeline.identifier, true).then(result => {
btnLaunchContent.enabled = true;
if (!result.success) { if (!result.success) {
console.error("setWallpaperAtTimelineIndex failed"); InstantPopup.openErrorPopup(timeline, result.message);
return; return;
} }
}); });
} }
btnLaunchContent.enabled = true;
root.close(); root.close();
monitorSelection.reset(); // monitorSelection.reset()
} }
} }
} }

View File

@ -155,7 +155,7 @@ Item {
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignHCenter
} }
ScreenPlayItemImage { InstalledItemImage {
id: screenPlayItemImage id: screenPlayItemImage
opacity: root.hasLicense ? 1 : 0.3 opacity: root.hasLicense ? 1 : 0.3
anchors.fill: parent anchors.fill: parent

View File

@ -215,7 +215,7 @@ Item {
} }
} }
delegate: ScreenPlayItem { delegate: InstalledItem {
id: delegate id: delegate
objectName: "installedItem" + index objectName: "installedItem" + index
focus: true focus: true

View File

@ -314,6 +314,7 @@ Rectangle {
rightMargin: 10 rightMargin: 10
bottom: parent.bottom bottom: parent.bottom
} }
Material.accent: contentActive ? "gold" : Material.secondaryTextColor Material.accent: contentActive ? "gold" : Material.secondaryTextColor
property bool contentActive: App.screenPlayManager.activeWallpaperCounter > 0 property bool contentActive: App.screenPlayManager.activeWallpaperCounter > 0

View File

@ -11,6 +11,9 @@
#include <QDebug> #include <QDebug>
#include <QRandomGenerator> #include <QRandomGenerator>
#include "ScreenPlay/CMakeVariables.h"
#include <type_traits>
namespace ScreenPlay { namespace ScreenPlay {
/*! /*!
@ -34,6 +37,8 @@ namespace ScreenPlay {
MonitorListModel::MonitorListModel(QObject* parent) MonitorListModel::MonitorListModel(QObject* parent)
: QAbstractListModel(parent) : QAbstractListModel(parent)
{ {
static_assert(SCREENPLAY_DEPLOY_VERSION == 0 || !std::is_same_v<decltype(m_useMockMonitors), bool>,
"Mock monitors should not be available in deploy version");
auto* guiAppInst = dynamic_cast<QGuiApplication*>(QGuiApplication::instance()); auto* guiAppInst = dynamic_cast<QGuiApplication*>(QGuiApplication::instance());
connect(guiAppInst, &QGuiApplication::screenAdded, this, &MonitorListModel::screenAdded); connect(guiAppInst, &QGuiApplication::screenAdded, this, &MonitorListModel::screenAdded);
@ -70,6 +75,7 @@ QHash<int, QByteArray> MonitorListModel::roleNames() const
{ {
static const QHash<int, QByteArray> roles { static const QHash<int, QByteArray> roles {
{ static_cast<int>(MonitorRole::AppID), "m_appID" }, { static_cast<int>(MonitorRole::AppID), "m_appID" },
{ static_cast<int>(MonitorRole::AppState), "m_appState" },
{ static_cast<int>(MonitorRole::Index), "m_index" }, { static_cast<int>(MonitorRole::Index), "m_index" },
{ static_cast<int>(MonitorRole::Geometry), "m_geometry" }, { static_cast<int>(MonitorRole::Geometry), "m_geometry" },
{ static_cast<int>(MonitorRole::PreviewImage), "m_previewImage" }, { static_cast<int>(MonitorRole::PreviewImage), "m_previewImage" },
@ -110,6 +116,8 @@ QVariant MonitorListModel::data(const QModelIndex& index, int role) const
switch (roleEnum) { switch (roleEnum) {
case MonitorRole::AppID: case MonitorRole::AppID:
return m_monitorList.at(row).m_appID; return m_monitorList.at(row).m_appID;
case MonitorRole::AppState:
return QVariant::fromValue(m_monitorList.at(row).m_appState);
case MonitorRole::Index: case MonitorRole::Index:
return m_monitorList.at(row).m_index; return m_monitorList.at(row).m_index;
case MonitorRole::Geometry: case MonitorRole::Geometry:
@ -267,6 +275,10 @@ bool MonitorListModel::setData(const QModelIndex& index, const QVariant& value,
m_monitorList[index.column()].m_appID = value.toString(); m_monitorList[index.column()].m_appID = value.toString();
emit dataChanged(index, index, { role }); emit dataChanged(index, index, { role });
} }
if (role == static_cast<int>(MonitorRole::AppState)) {
m_monitorList[index.column()].m_appState = static_cast<ScreenPlayEnums::AppState>(value.toInt());
emit dataChanged(index, index, { role });
}
if (role == static_cast<int>(MonitorRole::InstalledType)) { if (role == static_cast<int>(MonitorRole::InstalledType)) {
m_monitorList[index.column()].m_installedType = static_cast<ContentTypes::InstalledType>(value.toInt()); m_monitorList[index.column()].m_installedType = static_cast<ContentTypes::InstalledType>(value.toInt());
emit dataChanged(index, index, { role }); emit dataChanged(index, index, { role });

View File

@ -2,6 +2,7 @@
#include "ScreenPlay/screenplaymanager.h" #include "ScreenPlay/screenplaymanager.h"
#include "ScreenPlayUtil/util.h" #include "ScreenPlayUtil/util.h"
#include "core/qcorothread.h"
#include <QScopeGuard> #include <QScopeGuard>
namespace ScreenPlay { namespace ScreenPlay {
@ -27,6 +28,10 @@ ScreenPlayManager::ScreenPlayManager(
QObject::connect(m_server.get(), &QLocalServer::newConnection, this, &ScreenPlayManager::newConnection); QObject::connect(m_server.get(), &QLocalServer::newConnection, this, &ScreenPlayManager::newConnection);
QObject::connect(&m_screenPlayTimelineManager, &ScreenPlayTimelineManager::requestSaveProfiles, this, &ScreenPlayManager::requestSaveProfiles); QObject::connect(&m_screenPlayTimelineManager, &ScreenPlayTimelineManager::requestSaveProfiles, this, &ScreenPlayManager::requestSaveProfiles);
QObject::connect(&m_screenPlayTimelineManager, &ScreenPlayTimelineManager::activeWallpaperCountChanged, this, &ScreenPlayManager::setActiveWallpaperCounter); QObject::connect(&m_screenPlayTimelineManager, &ScreenPlayTimelineManager::activeWallpaperCountChanged, this, &ScreenPlayManager::setActiveWallpaperCounter);
QObject::connect(this, &ScreenPlayManager::selectedTimelineIndexChanged, &m_screenPlayTimelineManager, &ScreenPlayTimelineManager::setSelectedTimelineIndex);
QObject::connect(this, &ScreenPlayManager::selectedTimelineIndexChanged, &m_screenPlayTimelineManager, &ScreenPlayTimelineManager::updateMonitorListModelData);
m_server->setSocketOptions(QLocalServer::WorldAccessOption); m_server->setSocketOptions(QLocalServer::WorldAccessOption);
if (!m_server->listen("ScreenPlay")) { if (!m_server->listen("ScreenPlay")) {
qCritical("Could not open Local Socket with the name ScreenPlay!"); qCritical("Could not open Local Socket with the name ScreenPlay!");
@ -37,9 +42,6 @@ ScreenPlayManager::ScreenPlayManager(
// we limit ourself to m_saveLimiters interval below: // we limit ourself to m_saveLimiters interval below:
m_saveLimiter.setInterval(1000); m_saveLimiter.setInterval(1000);
QObject::connect(&m_saveLimiter, &QTimer::timeout, this, &ScreenPlayManager::saveProfiles); QObject::connect(&m_saveLimiter, &QTimer::timeout, this, &ScreenPlayManager::saveProfiles);
QObject::connect(this, &ScreenPlayManager::requestSaveProfiles, this, [this]() {
m_saveLimiter.start();
});
} }
/*! /*!
@ -90,23 +92,29 @@ QCoro::QmlTask ScreenPlayManager::setWallpaperAtTimelineIndex(
return QCoro::QmlTask([this, wallpaperData, timelineIndex, identifier]() -> QCoro::Task<Result> { return QCoro::QmlTask([this, wallpaperData, timelineIndex, identifier]() -> QCoro::Task<Result> {
if (timelineIndex < 0 || identifier.isEmpty()) { if (timelineIndex < 0 || identifier.isEmpty()) {
const QString msg = QString("Invalid timeline index %1 identifier %2").arg(QString::number(timelineIndex), identifier);
co_return Result { false }; Result result;
result.setSuccess(false);
result.setMessage(msg);
co_return result;
} }
const bool success = co_await m_screenPlayTimelineManager.setWallpaperAtTimelineIndex(wallpaperData, timelineIndex, identifier); const bool success = co_await m_screenPlayTimelineManager.setWallpaperAtTimelineIndex(wallpaperData, timelineIndex, identifier);
if (!success) { if (!success) {
qCritical() << "Invalid timeline index or identifier: " << timelineIndex << identifier; const QString msg = QString("Unable to setWallpaperAtTimelineIndex");
m_screenPlayTimelineManager.printTimelines(); m_screenPlayTimelineManager.printTimelines();
emit printQmlTimeline(); emit printQmlTimeline();
co_return Result { success }; Result result;
result.setSuccess(false);
result.setMessage(msg);
co_return result;
} }
// We do not start the wallpaper here, but let // We do not start the wallpaper here, but let
// ScreenPlayTimelineManager::checkActiveWallpaperTimeline decide // ScreenPlayTimelineManager::checkActiveWallpaperTimeline decide
// if the wallpaper // if the wallpaper
emit requestSaveProfiles(); // QMetaObject::invokeMethod(this, &ScreenPlayManager::requestSaveProfiles, Qt::QueuedConnection);
co_return Result { success }; co_return Result { success };
}()); }());
} }
@ -125,7 +133,7 @@ bool ScreenPlayManager::startWidget(
auto saveToProfile = qScopeGuard([=, this] { auto saveToProfile = qScopeGuard([=, this] {
// Do not save on app start // Do not save on app start
if (saveToProfilesConfigFile) { if (saveToProfilesConfigFile) {
emit requestSaveProfiles(); requestSaveProfiles();
} }
}); });
@ -157,11 +165,6 @@ bool ScreenPlayManager::startWidget(
return true; return true;
} }
void ScreenPlayManager::setSelectedTimelineIndex(const int selectedTimelineIndex)
{
m_screenPlayTimelineManager.updateMonitorListModelData(selectedTimelineIndex);
}
/*! /*!
\brief Removes all wallpaper entries in the profiles.json. \brief Removes all wallpaper entries in the profiles.json.
*/ */
@ -172,7 +175,8 @@ QCoro::QmlTask ScreenPlayManager::removeAllRunningWallpapers(bool saveToProfile)
const bool success = co_await m_screenPlayTimelineManager.removeAllWallpaperFromActiveTimlineSections(); const bool success = co_await m_screenPlayTimelineManager.removeAllWallpaperFromActiveTimlineSections();
qDebug() << "Task: removeAllWallpaperFromActiveTimlineSections" << success; qDebug() << "Task: removeAllWallpaperFromActiveTimlineSections" << success;
if (saveToProfile) if (saveToProfile)
emit requestSaveProfiles(); // QMetaObject::invokeMethod(this, &ScreenPlayManager::requestSaveProfiles, Qt::QueuedConnection);
m_screenPlayTimelineManager.updateMonitorListModelData(selectedTimelineIndex());
co_return Result { success }; co_return Result { success };
}()); }());
} }
@ -199,7 +203,7 @@ bool ScreenPlayManager::removeAllRunningWidgets(bool saveToProfile)
} }
if (saveToProfile) if (saveToProfile)
emit requestSaveProfiles(); requestSaveProfiles();
return true; return true;
} }
@ -211,12 +215,16 @@ bool ScreenPlayManager::removeAllRunningWidgets(bool saveToProfile)
*/ */
QCoro::QmlTask ScreenPlayManager::removeWallpaperAt(int timelineIndex, QString timelineIdentifier, int monitorIndex) QCoro::QmlTask ScreenPlayManager::removeWallpaperAt(int timelineIndex, QString timelineIdentifier, int monitorIndex)
{ {
qInfo() << "this: " << this;
return QCoro::QmlTask([this, timelineIndex, timelineIdentifier, monitorIndex]() -> QCoro::Task<Result> { return QCoro::QmlTask([this, timelineIndex, timelineIdentifier, monitorIndex]() -> QCoro::Task<Result> {
// call with coro
const bool success = co_await m_screenPlayTimelineManager.removeWallpaperAt(timelineIndex, timelineIdentifier, monitorIndex); const bool success = co_await m_screenPlayTimelineManager.removeWallpaperAt(timelineIndex, timelineIdentifier, monitorIndex);
qDebug() << "Task: removeAllWallpaperFromActiveTimlineSections" << success; qDebug() << "Task: removeAllWallpaperFromActiveTimlineSections" << success;
emit requestSaveProfiles();
// Use QMetaObject::invokeMethod to call requestSaveProfiles on the main thread
QMetaObject::invokeMethod(nullptr, "requestSaveProfiles", Qt::QueuedConnection);
m_screenPlayTimelineManager.updateMonitorListModelData(selectedTimelineIndex());
co_return Result { success }; co_return Result { success };
}()); }());
} }
@ -331,6 +339,7 @@ QCoro::QmlTask ScreenPlayManager::removeAllTimlineSections()
qDebug() << "Task: removeAllTimlineSections" << success; qDebug() << "Task: removeAllTimlineSections" << success;
// emit requestSaveProfiles(); // emit requestSaveProfiles();
// removeAllRunningWallpapers(); // removeAllRunningWallpapers();
// QMetaObject::invokeMethod(this, &ScreenPlayManager::requestSaveProfiles, Qt::QueuedConnection);
co_return Result { success }; co_return Result { success };
}()); }());
} }
@ -338,7 +347,7 @@ QCoro::QmlTask ScreenPlayManager::removeAllTimlineSections()
bool ScreenPlayManager::removeTimelineAt(const int index) bool ScreenPlayManager::removeTimelineAt(const int index)
{ {
const bool success = m_screenPlayTimelineManager.removeTimelineAt(index); const bool success = m_screenPlayTimelineManager.removeTimelineAt(index);
emit requestSaveProfiles(); requestSaveProfiles();
return success; return success;
} }
/*! /*!
@ -426,52 +435,6 @@ void ScreenPlayManager::setActiveWidgetsCounter(int activeWidgetsCounter)
emit activeWidgetsCounterChanged(m_activeWidgetsCounter); emit activeWidgetsCounterChanged(m_activeWidgetsCounter);
} }
/*!
\brief Removes a wallpaper from the given appID. Returns true on success.
*/
bool ScreenPlayManager::removeWallpaper(const QString& appID)
{
auto wallpaperSectionOpt = m_screenPlayTimelineManager.activeWallpaperSectionByAppID(appID);
if (!wallpaperSectionOpt.has_value()) {
qCritical() << "No wallpaper found.";
return false;
}
if (!wallpaperSectionOpt.value()) {
qCritical() << "No wallpaperSectionOpt invalid.";
return false;
}
auto& wallpaperSection = wallpaperSectionOpt.value();
wallpaperSection->activeWallpaperList.erase(
std::remove_if(
wallpaperSection->activeWallpaperList.begin(),
wallpaperSection->activeWallpaperList.end(),
[this, appID](std::shared_ptr<ScreenPlayWallpaper>& wallpaper) {
if (wallpaper->appID() != appID) {
return false;
}
qInfo() << "Remove wallpaper " << wallpaper->file() << "at monitor " << wallpaper->monitors();
// The MonitorListModel contains a shared_ptr of this object that needs to be removed
// for shared_ptr to release the object.
// m_monitorListModel->setWallpaperMonitor({}, wallpaper->monitors());
wallpaper->close();
return true;
}));
if (activeWallpaperCounter() != wallpaperSection->activeWallpaperList.size()) {
qWarning() << "activeWallpaperCounter value: " << activeWallpaperCounter()
<< "does not match m_screenPlayWallpapers length:" << wallpaperSection->activeWallpaperList.size();
return false;
}
return true;
}
/*! /*!
\brief Removes a Widget from the given appID. Returns true on success. \brief Removes a Widget from the given appID. Returns true on success.
*/ */
@ -536,6 +499,11 @@ int ScreenPlayManager::activeTimelineIndex()
return activeTimelineSection->index; return activeTimelineSection->index;
} }
void ScreenPlayManager::requestSaveProfiles()
{
m_saveLimiter.start();
}
/*! /*!
\brief Saves a given wallpaper \a newProfileObject to a \a profileName. We ignore the profileName argument \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. because we currently only support one profile. Returns \c true if successfuly saved to profiles.json, otherwise \c false.
@ -658,6 +626,14 @@ bool ScreenPlayManager::loadWidgetConfig(const QJsonObject& widgetObj)
} }
return true; return true;
} }
void ScreenPlayManager::setSelectedTimelineIndex(int selectedTimelineIndex)
{
// if (m_selectedTimelineIndex == selectedTimelineIndex)
// return;
m_selectedTimelineIndex = selectedTimelineIndex;
emit selectedTimelineIndexChanged(m_selectedTimelineIndex);
}
} }
#include "moc_screenplaymanager.cpp" #include "moc_screenplaymanager.cpp"

View File

@ -7,6 +7,7 @@
#include <QStringList> #include <QStringList>
#include <iostream> #include <iostream>
#include <ranges> #include <ranges>
#include <unordered_set>
namespace ScreenPlay { namespace ScreenPlay {
@ -94,6 +95,9 @@ bool ScreenPlayTimelineManager::addTimelineFromSettings(const QJsonObject& timel
// TODO check license // TODO check license
auto newTimelineSection = std::make_shared<WallpaperTimelineSection>(); auto newTimelineSection = std::make_shared<WallpaperTimelineSection>();
QObject::connect(newTimelineSection.get(), &WallpaperTimelineSection::requestUpdateMonitorListModel, this, [this]() {
updateMonitorListModelData(selectedTimelineIndex());
});
QObject::connect(newTimelineSection.get(), &WallpaperTimelineSection::requestSaveProfiles, this, &ScreenPlayTimelineManager::requestSaveProfiles); QObject::connect(newTimelineSection.get(), &WallpaperTimelineSection::requestSaveProfiles, this, &ScreenPlayTimelineManager::requestSaveProfiles);
QObject::connect(newTimelineSection.get(), &WallpaperTimelineSection::activeWallpaperCountChanged, this, &ScreenPlayTimelineManager::activeWallpaperCountChanged); QObject::connect(newTimelineSection.get(), &WallpaperTimelineSection::activeWallpaperCountChanged, this, &ScreenPlayTimelineManager::activeWallpaperCountChanged);
newTimelineSection->startTime = startTime; newTimelineSection->startTime = startTime;
@ -181,6 +185,10 @@ void ScreenPlayTimelineManager::checkActiveWallpaperTimeline()
if (currentTimeline != activeTimeline) { if (currentTimeline != activeTimeline) {
activeTimeline->deactivateTimeline(); activeTimeline->deactivateTimeline();
currentTimeline->activateTimeline(); currentTimeline->activateTimeline();
} else {
if (activeTimeline->state == WallpaperTimelineSection::State::Inactive) {
currentTimeline->activateTimeline();
}
} }
} }
@ -221,41 +229,57 @@ void ScreenPlayTimelineManager::setMonitorListModel(const std::shared_ptr<Monito
void ScreenPlayTimelineManager::updateMonitorListModelData(const int selectedTimelineIndex) void ScreenPlayTimelineManager::updateMonitorListModelData(const int selectedTimelineIndex)
{ {
if (m_wallpaperTimelineSectionsList.isEmpty()) {
qCritical() << "No m_wallpaperTimelineSectionsList is empty";
return;
}
auto selectedTimeline = m_wallpaperTimelineSectionsList | std::views::drop(selectedTimelineIndex) | std::views::take(1); auto selectedTimeline = m_wallpaperTimelineSectionsList | std::views::drop(selectedTimelineIndex) | std::views::take(1);
// Clear current list model. This is needed to make sure
// that we do not show any old active wallpaper
if (selectedTimeline.empty()) { if (selectedTimeline.empty()) {
qCritical() << "No selectedTimelineIndex found" << selectedTimelineIndex; qCritical() << "No selectedTimelineIndex found" << selectedTimelineIndex;
return; return;
} }
std::shared_ptr<WallpaperTimelineSection>& timeline = selectedTimeline.front(); std::shared_ptr<WallpaperTimelineSection>& timeline = selectedTimeline.front();
m_monitorListModel->reset(); // Create a set of monitor indices that have active wallpapers
std::unordered_set<int> activeMonitors;
for (const auto& activeWallpaper : timeline->activeWallpaperList) {
for (const auto& monitorIndex : activeWallpaper->monitors()) {
activeMonitors.insert(monitorIndex);
}
}
for (int i = 0; i < m_monitorListModel->rowCount(); ++i) { for (int i = 0; i < m_monitorListModel->rowCount(); ++i) {
// One wallpaper can span across multiple monitors
bool ok; bool ok;
const int monitorIndex = m_monitorListModel->data(m_monitorListModel->index(i), (int)MonitorListModel::MonitorRole::Index).toInt(&ok); const int monitorIndex = m_monitorListModel->data(m_monitorListModel->index(i), (int)MonitorListModel::MonitorRole::Index).toInt(&ok);
if (!ok) { if (!ok) {
qCritical() << "Invalid monitor index at: " << i; qCritical() << "Invalid monitor index at: " << i;
return; return;
} }
for (const auto& wallpaper : timeline->wallpaperDataList) {
if (wallpaper.monitors.contains(monitorIndex)) { const auto modelIndex = m_monitorListModel->index(0, monitorIndex);
const auto previewImg = wallpaper.absolutePath + "/" + wallpaper.previewImage;
const auto mondelIndex = m_monitorListModel->index(0, monitorIndex); if (activeMonitors.find(monitorIndex) != activeMonitors.end()) {
m_monitorListModel->setData(mondelIndex, previewImg, (int)MonitorListModel::MonitorRole::PreviewImage); // Monitor has an active wallpaper
// TODO for (const auto& activeWallpaper : timeline->activeWallpaperList) {
m_monitorListModel->setData(mondelIndex, "dummy", (int)MonitorListModel::MonitorRole::AppID); if (activeWallpaper->monitors().contains(monitorIndex)) {
m_monitorListModel->setData(mondelIndex, (int)wallpaper.type, (int)MonitorListModel::MonitorRole::InstalledType); const auto previewImg = activeWallpaper->absolutePath() + "/" + activeWallpaper->previewImage();
break; m_monitorListModel->setData(modelIndex, activeWallpaper->appID(), (int)MonitorListModel::MonitorRole::AppID);
m_monitorListModel->setData(modelIndex, (int)activeWallpaper->state(), (int)MonitorListModel::MonitorRole::AppState);
m_monitorListModel->setData(modelIndex, previewImg, (int)MonitorListModel::MonitorRole::PreviewImage);
m_monitorListModel->setData(modelIndex, (int)activeWallpaper->type(), (int)MonitorListModel::MonitorRole::InstalledType);
break;
}
} }
} else {
// Reset monitor data to empty values
m_monitorListModel->setData(modelIndex, "", (int)MonitorListModel::MonitorRole::AppID);
m_monitorListModel->setData(modelIndex, 0, (int)MonitorListModel::MonitorRole::AppState);
m_monitorListModel->setData(modelIndex, "", (int)MonitorListModel::MonitorRole::PreviewImage);
m_monitorListModel->setData(modelIndex, 0, (int)MonitorListModel::MonitorRole::InstalledType);
} }
} }
} }
void ScreenPlayTimelineManager::setGlobalVariables(const std::shared_ptr<GlobalVariables>& globalVariables) void ScreenPlayTimelineManager::setGlobalVariables(const std::shared_ptr<GlobalVariables>& globalVariables)
{ {
m_globalVariables = globalVariables; m_globalVariables = globalVariables;
@ -368,7 +392,7 @@ bool ScreenPlayTimelineManager::addTimelineAt(const int index, const float relat
updateIndices(); updateIndices();
printTimelines(); printTimelines();
emit requestSaveProfiles(); // emit requestSaveProfiles();
return true; return true;
} }
@ -421,8 +445,10 @@ QCoro::Task<bool> ScreenPlayTimelineManager::removeWallpaperAt(const int timelin
}); });
std::optional<std::shared_ptr<WallpaperTimelineSection>> sectionOpt = wallpaperSection(timelineIndex, timelineIdentifier); std::optional<std::shared_ptr<WallpaperTimelineSection>> sectionOpt = wallpaperSection(timelineIndex, timelineIdentifier);
if (!sectionOpt) if (!sectionOpt) {
qCritical() << "No timeline section for timelineIndex" << timelineIndex << "timelineIdentifier" << timelineIdentifier << "monitorIndex" << monitorIndex;
co_return false; co_return false;
}
const bool success = co_await sectionOpt.value()->removeWallpaper(monitorIndex); const bool success = co_await sectionOpt.value()->removeWallpaper(monitorIndex);
@ -530,13 +556,19 @@ QCoro::Task<bool> ScreenPlayTimelineManager::setWallpaperAtTimelineIndex(
*it = wallpaperData; *it = wallpaperData;
// TODO: Do not replace but // TODO: Do not replace but
co_await timelineSection->deactivateTimeline(); co_await timelineSection->deactivateTimeline();
timelineSection->activateTimeline();
} else { } else {
// IMPORTANT: Append the new wallpaper data, // IMPORTANT: Append the new wallpaper data,
// but do not start it! The selected timelineSection // but do not start it! The selected timelineSection
// is not always be the currently running. // is not always be the currently running.
// Besides for this we have m_contentTimer checkActiveWallpaperTimeline() // Besides for this we have m_contentTimer checkActiveWallpaperTimeline()
timelineSection->wallpaperDataList.push_back(wallpaperData); timelineSection->wallpaperDataList.push_back(wallpaperData);
// If the updated timeline section is already active, we
// need to trigger a activateTimeline by deactivating it first
if (timelineSection->state == WallpaperTimelineSection::State::Active) {
qDebug() << "Deactivate current timeline first";
co_await timelineSection->deactivateTimeline();
}
} }
break; break;
@ -572,4 +604,17 @@ QJsonArray ScreenPlayTimelineManager::timelineWallpaperList()
} }
return timelineWallpaperList; return timelineWallpaperList;
} }
int ScreenPlayTimelineManager::selectedTimelineIndex() const
{
return m_selectedTimelineIndex;
}
void ScreenPlayTimelineManager::setSelectedTimelineIndex(int selectedTimelineIndex)
{
if (m_selectedTimelineIndex == selectedTimelineIndex)
return;
m_selectedTimelineIndex = selectedTimelineIndex;
emit selectedTimelineIndexChanged(m_selectedTimelineIndex);
}
} }

View File

@ -156,27 +156,36 @@ QJsonObject ScreenPlayWallpaper::getActiveSettingsJson()
*/ */
void ScreenPlayWallpaper::close() void ScreenPlayWallpaper::close()
{ {
setState(ScreenPlayEnums::AppState::Closing);
qInfo() << "Close wallpaper with appID:" << m_appID; qInfo() << "Close wallpaper with appID:" << m_appID;
m_pingAliveTimer.stop(); // Stop the timer when closing
// When the wallpaper never connected, this is invalid // When the wallpaper never connected, this is invalid
if (!m_connection) { if (!m_connection) {
qCritical() << "Cannot request quit, wallpaper never connected!"; qCritical() << "Cannot request quit, wallpaper never connected!";
setState(ScreenPlayEnums::AppState::Inactive);
return; return;
} }
if (!m_connection->close()) { if (!m_connection->close()) {
qCritical() << "Cannot close wallpaper!"; qCritical() << "Cannot close wallpaper!";
setState(ScreenPlayEnums::AppState::Inactive);
return; return;
} }
m_isExiting = true; // The state will be set to Inactive in the disconnected callback
} }
/*! /*!
\brief Prints the exit code if != 0. \brief Prints the exit code if != 0.
*/ */
void ScreenPlayWallpaper::processExit(int exitCode, QProcess::ExitStatus exitStatus) void ScreenPlayWallpaper::processExit(int exitCode, QProcess::ExitStatus exitStatus)
{ {
if (exitCode != 0) setState(ScreenPlay::ScreenPlayEnums::AppState::Inactive);
qWarning() << "WARNING EXIT CODE: " << exitCode << exitStatus; if (exitCode != 0) {
qCritical() << "ERROR: Wallpaper closed with appID: " << m_appID << " EXIT CODE: " << exitCode << exitStatus;
return;
}
qDebug() << "Wallpaper closed with appID: " << m_appID;
} }
/*! /*!
@ -184,6 +193,7 @@ void ScreenPlayWallpaper::processExit(int exitCode, QProcess::ExitStatus exitSta
*/ */
void ScreenPlayWallpaper::processError(QProcess::ProcessError error) void ScreenPlayWallpaper::processError(QProcess::ProcessError error)
{ {
setState(ScreenPlay::ScreenPlayEnums::AppState::Inactive);
qWarning() << "EX: " << error; qWarning() << "EX: " << error;
} }
@ -192,10 +202,13 @@ void ScreenPlayWallpaper::processError(QProcess::ProcessError error)
playbackRate or fillMode. Otherwise it is a simple key, value json pair. playbackRate or fillMode. Otherwise it is a simple key, value json pair.
*/ */
bool ScreenPlayWallpaper::setWallpaperValue(const QString& key, const QString& value, const bool save) bool ScreenPlayWallpaper::setWallpaperValue(const QString& key, const QString& value, const bool save)
{ {
if (m_isExiting) if (state() != ScreenPlayEnums::AppState::Active) {
qWarning() << "Cannot set value for inactive or closing wallpaper!";
return false; return false;
}
if (!m_connection) { if (!m_connection) {
qWarning() << "Cannot set value for unconnected wallpaper!"; qWarning() << "Cannot set value for unconnected wallpaper!";
@ -223,6 +236,16 @@ bool ScreenPlayWallpaper::setWallpaperValue(const QString& key, const QString& v
return success; return success;
} }
ScreenPlay::ScreenPlayEnums::AppState ScreenPlayWallpaper::state() const
{
return m_state;
}
void ScreenPlayWallpaper::setState(ScreenPlay::ScreenPlayEnums::AppState state)
{
m_state = state;
}
const WallpaperData& ScreenPlayWallpaper::wallpaperData() const WallpaperData& ScreenPlayWallpaper::wallpaperData()
{ {
return m_wallpaperData; return m_wallpaperData;
@ -237,11 +260,15 @@ void ScreenPlayWallpaper::setSDKConnection(std::unique_ptr<SDKConnection> connec
m_connection = std::move(connection); m_connection = std::move(connection);
qInfo() << "[4/4] SDKConnection (Wallpaper) saved!"; qInfo() << "[4/4] SDKConnection (Wallpaper) saved!";
setIsConnected(true); setIsConnected(true);
setState(ScreenPlayEnums::AppState::Active);
QObject::connect(m_connection.get(), &SDKConnection::disconnected, this, [this]() { QObject::connect(m_connection.get(), &SDKConnection::disconnected, this, [this]() {
setIsConnected(false); setIsConnected(false);
setState(ScreenPlayEnums::AppState::Inactive);
m_pingAliveTimer.stop(); // Stop the timer when disconnected
qInfo() << "Wallpaper:" << m_connection->appID() << "disconnected"; qInfo() << "Wallpaper:" << m_connection->appID() << "disconnected";
}); });
QTimer::singleShot(1000, this, [this]() { QTimer::singleShot(1000, this, [this]() {
if (playbackRate() != 1.0) { if (playbackRate() != 1.0) {
setWallpaperValue("playbackRate", QString::number(playbackRate()), false); setWallpaperValue("playbackRate", QString::number(playbackRate()), false);
@ -249,6 +276,7 @@ void ScreenPlayWallpaper::setSDKConnection(std::unique_ptr<SDKConnection> connec
QObject::connect(&m_pingAliveTimer, &QTimer::timeout, this, [this]() { QObject::connect(&m_pingAliveTimer, &QTimer::timeout, this, [this]() {
qInfo() << "For " << m_pingAliveTimer.interval() << "ms no alive signal received. This means the Wallpaper is dead and likely crashed!"; qInfo() << "For " << m_pingAliveTimer.interval() << "ms no alive signal received. This means the Wallpaper is dead and likely crashed!";
setState(ScreenPlayEnums::AppState::Closing);
emit requestClose(m_appID); emit requestClose(m_appID);
}); });
m_pingAliveTimer.start(GlobalVariables::contentPingAliveIntervalMS); m_pingAliveTimer.start(GlobalVariables::contentPingAliveIntervalMS);
@ -256,15 +284,17 @@ void ScreenPlayWallpaper::setSDKConnection(std::unique_ptr<SDKConnection> connec
// Check every X seconds if the wallpaper is still alive // Check every X seconds if the wallpaper is still alive
QObject::connect(m_connection.get(), &SDKConnection::pingAliveReceived, this, [this]() { QObject::connect(m_connection.get(), &SDKConnection::pingAliveReceived, this, [this]() {
m_pingAliveTimer.stop(); if (state() == ScreenPlayEnums::AppState::Active) {
m_pingAliveTimer.start(GlobalVariables::contentPingAliveIntervalMS); m_pingAliveTimer.stop();
m_pingAliveTimer.start(GlobalVariables::contentPingAliveIntervalMS);
std::optional<bool> running = m_processManager.isRunning(m_processID); std::optional<bool> running = m_processManager.isRunning(m_processID);
if (running.has_value()) { if (running.has_value()) {
qInfo() << "running:" << running.value(); // qInfo() << "running:" << running.value();
} else { } else {
qInfo() << "INVALID PID:" << m_processID; qInfo() << "INVALID PID:" << m_processID;
}
} }
}); });
} }
@ -276,9 +306,10 @@ bool ScreenPlayWallpaper::replace(
const WallpaperData wallpaperData, const WallpaperData wallpaperData,
const bool checkWallpaperVisible) const bool checkWallpaperVisible)
{ {
if (state() != ScreenPlayEnums::AppState::Active) {
if (m_isExiting) qWarning() << "Cannot replace inactive or closing wallpaper!";
return false; return false;
}
if (!m_connection) { if (!m_connection) {
qWarning() << "Cannot replace for unconnected wallpaper!"; qWarning() << "Cannot replace for unconnected wallpaper!";
@ -300,7 +331,6 @@ bool ScreenPlayWallpaper::replace(
emit requestSave(); emit requestSave();
return success; return success;
} }
} }
#include "moc_screenplaywallpaper.cpp" #include "moc_screenplaywallpaper.cpp"

View File

@ -41,7 +41,7 @@ QJsonObject WallpaperTimelineSection::serialize() const
// Start all ScreenPlayWallpaper processes of this current timeline // Start all ScreenPlayWallpaper processes of this current timeline
bool WallpaperTimelineSection::activateTimeline() bool WallpaperTimelineSection::activateTimeline()
{ {
if (state == State::Active) { if (state != State::Inactive) {
qCritical() << " timeline:" << index << identifier << "is already active with state: " << state; qCritical() << " timeline:" << index << identifier << "is already active with state: " << state;
return false; return false;
} }
@ -80,6 +80,7 @@ bool WallpaperTimelineSection::activateTimeline()
// &ScreenPlayManager::requestSaveProfiles // &ScreenPlayManager::requestSaveProfiles
emit requestSaveProfiles(); emit requestSaveProfiles();
}); });
QObject::connect(screenPlayWallpaper.get(), &ScreenPlayWallpaper::stateChanged, this, &WallpaperTimelineSection::requestUpdateMonitorListModel);
QObject::connect(screenPlayWallpaper.get(), &ScreenPlayWallpaper::requestClose, this, [this]() { QObject::connect(screenPlayWallpaper.get(), &ScreenPlayWallpaper::requestClose, this, [this]() {
// , &ScreenPlayManager::removeWallpaper); // , &ScreenPlayManager::removeWallpaper);
}); });
@ -100,6 +101,11 @@ bool WallpaperTimelineSection::activateTimeline()
QCoro::Task<bool> WallpaperTimelineSection::deactivateTimeline() QCoro::Task<bool> WallpaperTimelineSection::deactivateTimeline()
{ {
if (state != State::Active) {
qCritical() << " timeline:" << index << identifier << "is already active with state: " << state;
co_return false;
}
state = WallpaperTimelineSection::State::Closing; state = WallpaperTimelineSection::State::Closing;
if (activeWallpaperList.empty()) { if (activeWallpaperList.empty()) {
state = State::Inactive; state = State::Inactive;
@ -149,33 +155,30 @@ QCoro::Task<bool> WallpaperTimelineSection::deactivateTimeline()
// WallpaperData! // WallpaperData!
QCoro::Task<bool> WallpaperTimelineSection::removeWallpaper(const int monitorIndex) QCoro::Task<bool> WallpaperTimelineSection::removeWallpaper(const int monitorIndex)
{ {
// Remove WallpaperData first
size_t removedCount = std::erase_if(wallpaperDataList, [monitorIndex](const auto& wallpaperData) { size_t removedCount = std::erase_if(wallpaperDataList, [monitorIndex](const auto& wallpaperData) {
return wallpaperData.monitors.contains(monitorIndex); return wallpaperData.monitors.contains(monitorIndex);
}); });
if (removedCount == 0) { if (removedCount == 0) {
qCritical() << "No wallpaper data found for monitor index:" << monitorIndex; qCritical() << "No wallpaper data found for monitor index:" << monitorIndex;
co_return false; co_return false;
} }
std::shared_ptr<ScreenPlayWallpaper> runningScreenPlayWallpaper; std::shared_ptr<ScreenPlayWallpaper> runningScreenPlayWallpaper;
bool found = false; auto it = std::find_if(activeWallpaperList.begin(), activeWallpaperList.end(),
for (const auto& screenPlayWallpaper : activeWallpaperList) { [monitorIndex](const auto& screenPlayWallpaper) {
if (screenPlayWallpaper->monitors().contains(monitorIndex)) { return screenPlayWallpaper->monitors().contains(monitorIndex);
runningScreenPlayWallpaper = screenPlayWallpaper; });
found = true;
break;
}
}
// The user always can select a not running timeline section // The user always can select a not running timeline section
// and remove the wallpaper there. This means that it is // and remove the wallpaper there. This means that it is
// fine to just return here. // fine to just return here.
if (!found) { if (it == activeWallpaperList.end()) {
qDebug() << "No running wallpaper found for monitor index:" << monitorIndex; qDebug() << "No running wallpaper found for monitor index:" << monitorIndex;
co_return true; co_return true;
} }
runningScreenPlayWallpaper = *it;
QTimer timer; QTimer timer;
timer.start(250); timer.start(250);
const int maxRetries = 30; const int maxRetries = 30;
@ -184,9 +187,14 @@ QCoro::Task<bool> WallpaperTimelineSection::removeWallpaper(const int monitorInd
// Wait for the timer to tick // Wait for the timer to tick
co_await timer; co_await timer;
if (!runningScreenPlayWallpaper->isConnected()) { if (!runningScreenPlayWallpaper->isConnected()) {
// Remove the wallpaper from the activeWallpaperList
activeWallpaperList.erase(it);
updateActiveWallpaperCounter();
co_return true; co_return true;
} }
} }
qCritical() << "Failed to close wallpaper for monitor index:" << monitorIndex;
co_return false; co_return false;
} }

View File

@ -38,7 +38,7 @@ void ScreenPlaySDK::start()
m_socket.connectToServer("ScreenPlay"); m_socket.connectToServer("ScreenPlay");
if (!m_socket.waitForConnected(1000)) { if (!m_socket.waitForConnected(1000)) {
emit disconnected(); disconnected();
} }
} }

View File

@ -23,6 +23,7 @@ set(QML
qml/Dialogs/CriticalError.qml qml/Dialogs/CriticalError.qml
qml/Dialogs/MonitorConfiguration.qml qml/Dialogs/MonitorConfiguration.qml
qml/Dialogs/SteamNotAvailable.qml qml/Dialogs/SteamNotAvailable.qml
qml/ErrorPopup.qml
qml/FileDropAnimation.qml qml/FileDropAnimation.qml
qml/FileSelector.qml qml/FileSelector.qml
qml/Grow.qml qml/Grow.qml
@ -30,11 +31,13 @@ set(QML
qml/Headline.qml qml/Headline.qml
qml/HeadlineSection.qml qml/HeadlineSection.qml
qml/ImageSelector.qml qml/ImageSelector.qml
qml/InstantPopup.js
qml/LabelSlider.qml qml/LabelSlider.qml
qml/LicenseSelector.qml qml/LicenseSelector.qml
qml/ModalBackgroundBlur.qml qml/ModalBackgroundBlur.qml
qml/MouseHoverBlocker.qml qml/MouseHoverBlocker.qml
qml/Popup.qml qml/Popup.qml
qml/RainbowGradient.qml
qml/RippleEffect.qml qml/RippleEffect.qml
qml/Shake.qml qml/Shake.qml
qml/Tag.qml qml/Tag.qml
@ -57,6 +60,7 @@ set(HEADER
inc/public/ScreenPlayUtil/archive.h inc/public/ScreenPlayUtil/archive.h
inc/public/ScreenPlayUtil/contenttypes.h inc/public/ScreenPlayUtil/contenttypes.h
inc/public/ScreenPlayUtil/exitcodes.h inc/public/ScreenPlayUtil/exitcodes.h
inc/public/ScreenPlayUtil/globalenums.h
inc/public/ScreenPlayUtil/HelpersCommon.h inc/public/ScreenPlayUtil/HelpersCommon.h
inc/public/ScreenPlayUtil/ListPropertyHelper.h inc/public/ScreenPlayUtil/ListPropertyHelper.h
inc/public/ScreenPlayUtil/logginghandler.h inc/public/ScreenPlayUtil/logginghandler.h

View File

@ -0,0 +1,27 @@
// SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only
#pragma once
#include <QObject>
#include <QQmlEngine>
#include <QtCore/qmetatype.h>
namespace ScreenPlay {
class ScreenPlayEnums : public QObject {
Q_OBJECT
QML_ELEMENT
Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
/*!
\brief Used in the "Installed" tab.
*/
public:
enum class AppState {
Inactive,
Starting,
Closing,
Active,
};
Q_ENUM(AppState)
};
}

View File

@ -0,0 +1,34 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Window
Popup {
id: root
modal: true
closePolicy: Popup.CloseOnEscape | Popup.CloseOnPressOutside
anchors.centerIn: Overlay.overlay
property string errorMessage: ""
contentItem: Column {
spacing: 10
Label {
text: qsTr("⚠️ Fatal error encountered:\n")
font.pointSize: 16
font.bold: true
}
Label {
text: root.errorMessage
wrapMode: Text.WordWrap
}
Row {
spacing: 10
Button {
text: qsTr("Ok")
onClicked: {
root.close();
}
}
}
}
}

View File

@ -0,0 +1,32 @@
.pragma library
.import QtQuick as QtQ
var errorPopup
/*
Creates error popups in js
*/
function openErrorPopup(parent, errorMsg) {
console.error(errorMsg)
// Check if parent is a valid QML Item
if (!(parent instanceof QtQ.Item)) {
console.error(
"Error: Invalid parent object provided. Parent must be a QML Item or inherit from it.",
typeof (parent))
return
}
if (!errorPopup) {
var errorComponent = Qt.createComponent(
"qrc:/qml/ScreenPlayUtil/qml/ErrorPopup.qml")
if (errorComponent.status === QtQ.Component.Ready) {
errorPopup = errorComponent.createObject(parent)
} else {
console.error("Error creating ErrorPopup:",
errorComponent.errorString())
return
}
}
errorPopup.errorMessage = errorMsg
errorPopup.open()
}

View File

@ -0,0 +1,172 @@
import QtQuick
Rectangle {
id: root
implicitHeight: 100
implicitWidth: 100
property int animationDuration: 2000
property bool running: true
gradient: Gradient {
orientation: Gradient.Horizontal
GradientStop {
id: stop1
position: -0.25
color: "#f79533"
}
GradientStop {
id: stop2
position: -0.11
color: "#f37055"
}
GradientStop {
id: stop3
position: 0.03
color: "#ef4e7b"
}
GradientStop {
id: stop4
position: 0.17
color: "#a166ab"
}
GradientStop {
id: stop5
position: 0.31
color: "#5073b8"
}
GradientStop {
id: stop6
position: 0.45
color: "#1098ad"
}
GradientStop {
id: stop7
position: 0.59
color: "#07b39b"
}
GradientStop {
id: stop8
position: 0.75
color: "#6fba82"
}
}
SequentialAnimation {
running: root.running
loops: Animation.Infinite
ParallelAnimation {
NumberAnimation {
target: stop1
property: "position"
from: -0.25
to: 0.25
duration: root.animationDuration
}
NumberAnimation {
target: stop2
property: "position"
from: -0.11
to: 0.39
duration: root.animationDuration
}
NumberAnimation {
target: stop3
property: "position"
from: 0.03
to: 0.53
duration: root.animationDuration
}
NumberAnimation {
target: stop4
property: "position"
from: 0.17
to: 0.67
duration: root.animationDuration
}
NumberAnimation {
target: stop5
property: "position"
from: 0.31
to: 0.81
duration: root.animationDuration
}
NumberAnimation {
target: stop6
property: "position"
from: 0.45
to: 0.95
duration: root.animationDuration
}
NumberAnimation {
target: stop7
property: "position"
from: 0.59
to: 1.09
duration: root.animationDuration
}
NumberAnimation {
target: stop8
property: "position"
from: 0.75
to: 1.25
duration: root.animationDuration
}
}
ParallelAnimation {
NumberAnimation {
target: stop1
property: "position"
from: 0.25
to: -0.25
duration: root.animationDuration
}
NumberAnimation {
target: stop2
property: "position"
from: 0.39
to: -0.11
duration: root.animationDuration
}
NumberAnimation {
target: stop3
property: "position"
from: 0.53
to: 0.03
duration: root.animationDuration
}
NumberAnimation {
target: stop4
property: "position"
from: 0.67
to: 0.17
duration: root.animationDuration
}
NumberAnimation {
target: stop5
property: "position"
from: 0.81
to: 0.31
duration: root.animationDuration
}
NumberAnimation {
target: stop6
property: "position"
from: 0.95
to: 0.45
duration: root.animationDuration
}
NumberAnimation {
target: stop7
property: "position"
from: 1.09
to: 0.59
duration: root.animationDuration
}
NumberAnimation {
target: stop8
property: "position"
from: 1.25
to: 0.75
duration: root.animationDuration
}
}
}
}

View File

@ -18,10 +18,10 @@ set(QML
# cmake-format: sort # cmake-format: sort
qml/Background.qml qml/Background.qml
qml/Forum.qml qml/Forum.qml
qml/InstalledItem.qml
qml/InstalledItemImage.qml
qml/Navigation.qml qml/Navigation.qml
qml/PopupOffline.qml qml/PopupOffline.qml
qml/ScreenPlayItem.qml
qml/ScreenPlayItemImage.qml
qml/Sidebar.qml qml/Sidebar.qml
qml/SteamProfile.qml qml/SteamProfile.qml
qml/SteamWorkshop.qml qml/SteamWorkshop.qml

View File

@ -147,7 +147,7 @@ Item {
anchors.fill: parent anchors.fill: parent
visible: false visible: false
ScreenPlayItemImage { InstalledItemImage {
id: screenPlayItemImage id: screenPlayItemImage
anchors.fill: parent anchors.fill: parent

View File

@ -141,7 +141,7 @@ Item {
margins: 5 margins: 5
} }
ScreenPlayItemImage { InstalledItemImage {
id: screenPlayItemImage id: screenPlayItemImage
anchors.fill: parent anchors.fill: parent

View File

@ -8,7 +8,6 @@ FetchContent_Populate(
# https://bugreports.qt.io/browse/QTCREATORBUG-27083 # https://bugreports.qt.io/browse/QTCREATORBUG-27083
SOURCE_DIR ${THIRD_PARTY_PATH}/QArchive) SOURCE_DIR ${THIRD_PARTY_PATH}/QArchive)
FetchContent_Populate( FetchContent_Populate(
qcoro qcoro
GIT_REPOSITORY https://github.com/danvratil/qcoro.git GIT_REPOSITORY https://github.com/danvratil/qcoro.git