1
0
mirror of https://gitlab.com/kelteseth/ScreenPlay.git synced 2024-09-14 22:42:34 +02: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
# cmake-format: sort
src/wallpaperdata.cpp
src/wallpapertimelinesection.cpp
src/screenplaytimelinemanager.cpp
src/app.cpp
src/applicationengine.cpp
src/create.cpp
@ -24,17 +21,17 @@ set(SOURCES
src/profilelistmodel.cpp
src/projectsettingslistmodel.cpp
src/screenplaymanager.cpp
src/screenplaytimelinemanager.cpp
src/screenplaywallpaper.cpp
src/screenplaywidget.cpp
src/sdkconnection.cpp
src/settings.cpp
src/wallpaperdata.cpp
src/wallpapertimelinesection.cpp
src/wizards.cpp)
set(HEADER
# 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/applicationengine.h
inc/public/ScreenPlay/create.h
@ -48,24 +45,32 @@ set(HEADER
inc/public/ScreenPlay/profilelistmodel.h
inc/public/ScreenPlay/projectsettingslistmodel.h
inc/public/ScreenPlay/screenplaymanager.h
inc/public/ScreenPlay/screenplaytimelinemanager.h
inc/public/ScreenPlay/screenplaywallpaper.h
inc/public/ScreenPlay/screenplaywidget.h
inc/public/ScreenPlay/sdkconnection.h
inc/public/ScreenPlay/settings.h
inc/public/ScreenPlay/wallpaperdata.h
inc/public/ScreenPlay/wallpapertimelinesection.h
inc/public/ScreenPlay/wizards.h)
set(QML
# cmake-format: sort
main.qml
qml/MainApp.qml
qml/Components/TrayIcon.qml
qml/Community/CommunityNavItem.qml
qml/Community/CommunityView.qml
qml/Community/XMLNewsfeed.qml
qml/Components/LineHandle.qml
qml/Components/LineIndicator.qml
qml/Components/ScreenPlayProPopup.qml
qml/Components/Timeline.qml
qml/Community/CommunityNavItem.qml
qml/Community/CommunityView.qml
qml/Community/XMLNewsfeed.qml
qml/Components/TrayIcon.qml
qml/ContentSettings/ContentSettingsView.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/CreateView.qml
qml/Create/StartInfo.qml
@ -84,18 +89,13 @@ set(QML
qml/Create/Wizards/QMLWidget.qml
qml/Create/Wizards/WebsiteWallpaper.qml
qml/Create/Wizards/WizardPage.qml
qml/Installed/InstalledDrawer.qml
qml/Installed/InstalledItem.qml
qml/Installed/InstalledItemImage.qml
qml/Installed/InstalledNavigation.qml
qml/Installed/InstalledView.qml
qml/Installed/InstalledWelcomeScreen.qml
qml/Installed/ScreenPlayItem.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/MainApp.qml
qml/Navigation/ExitPopup.qml
qml/Navigation/Navigation.qml
qml/Settings/SettingBool.qml
@ -135,9 +135,9 @@ set(RESOURCES
assets/icons/brand_twitch.svg
assets/icons/brand_twitter.svg
assets/icons/exclamation-triangle-solid.svg
assets/icons/font-awsome/lock-solid.svg
assets/icons/font-awsome/close.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/rotate-right-solid.svg
assets/icons/icon_arrow_left.svg
@ -194,8 +194,6 @@ set(RESOURCES
assets/icons/item_banner_new.svg
assets/icons/monitor_setup.svg
assets/icons/steam_default_avatar.png
assets/images/rocket_3d.png
assets/images/pro_version.png
assets/images/Intro.png
assets/images/Intro_PC.png
assets/images/Intro_shine.png
@ -204,6 +202,8 @@ set(RESOURCES
assets/images/missingPreview.png
assets/images/noisy-texture-3.png
assets/images/noisy-texture.png
assets/images/pro_version.png
assets/images/rocket_3d.png
assets/images/scale_window_indicator.png
assets/images/steam_offline.png
assets/images/trayIcon_osx.png

View File

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

View File

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

View File

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

View File

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

View File

@ -23,6 +23,7 @@ class WallpaperTimelineSection : public QObject {
QML_UNCREATABLE("")
Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
public:
// TODO: replace with wallpaper state?
enum class State {
Inactive,
Starting,
@ -46,6 +47,11 @@ public:
std::shared_ptr<GlobalVariables> globalVariables;
std::shared_ptr<Settings> settings;
signals:
void requestSaveProfiles();
void requestUpdateMonitorListModel();
void activeWallpaperCountChanged(const int count);
public:
// Check if currentTime falls within the timeline section
bool containsTime(const QTime& time) const;
@ -58,9 +64,5 @@ private slots:
private:
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.Controls
import ScreenPlayUtil as Util
Rectangle {
id: root
@ -26,9 +27,8 @@ Rectangle {
}
}
Rectangle {
Util.RainbowGradient {
opacity: root.isActive ? 1 : 0
color: "gold"
height: root.height
anchors {
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 {
id: indicatorLineVertical
width: 5
height: 30
height: root.selected ? 40 : 30
color: root.selected ? "gold" : parent.color
anchors {
horizontalCenter: parent.horizontalCenter
top: parent.bottom
topMargin: 0
}
Behavior on height {
NumberAnimation {
duration: 200
}
}
Behavior on color {
@ -94,6 +88,7 @@ Rectangle {
radius: 5
clip: true
color: Qt.darker(monitorBackground.color)
Image {
id: imgWallpaper
opacity: imgWallpaper.status === Image.Ready ? 1 : 0
@ -115,6 +110,7 @@ Rectangle {
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
root.lineSelected(root.index);
}

View File

@ -5,6 +5,7 @@ import QtQuick.Controls
import QtQuick.Layouts
import ScreenPlayApp
import ScreenPlayUtil
import "../../../ScreenPlayUtil/qml/InstantPopup.js" as InstantPopup
Control {
id: root
@ -121,7 +122,7 @@ Control {
if (timelineSection.wallpaperData.length === 0)
continue;
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;
App.screenPlayManager.removeAllRunningWallpapers().then(result => {
if (!result.success) {
console.error("removeAllTimlineSections failed");
InstantPopup.openErrorPopup(timeline, result.message);
btnReset.resetting = false;
return;
}
@ -523,7 +524,9 @@ Control {
const position = 1.0;
const identifier = App.util.generateRandomString(4);
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;
});
});

View File

@ -6,7 +6,7 @@ import QtQuick.Layouts
import QtQuick.Controls.Material.impl
import ScreenPlayApp
import ScreenPlayUtil as Util
import "../../../ScreenPlayUtil/qml/InstantPopup.js" as InstantPopup
import "../Components"
Util.Popup {
@ -149,7 +149,12 @@ Util.Popup {
monitorSelection.enabled = false;
App.screenPlayManager.removeWallpaperAt(index, selectedTimeline.identifier, selectedTimeline.index).then(result => {
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
anchors {
@ -179,23 +184,10 @@ Util.Popup {
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 {
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
highlighted: true
font.family: App.settings.font
@ -209,7 +201,7 @@ Util.Popup {
Button {
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.foreground: Material.primaryTextColor
highlighted: true

View File

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

View File

@ -9,6 +9,7 @@ Item {
property string previewImage
property string appID
property var installedType: ContentTypes.InstalledType.QMLWallpaper
property var appState: ScreenPlayEnums.AppState.Inactive
property bool monitorWithoutContentSelectable: true
property bool hasContent: appID !== ""
property int fontSize: 10
@ -85,6 +86,25 @@ Item {
asynchronous: true
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 {
anchors.fill: parent

View File

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

View File

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

View File

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

View File

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

View File

@ -11,6 +11,9 @@
#include <QDebug>
#include <QRandomGenerator>
#include "ScreenPlay/CMakeVariables.h"
#include <type_traits>
namespace ScreenPlay {
/*!
@ -34,6 +37,8 @@ namespace ScreenPlay {
MonitorListModel::MonitorListModel(QObject* 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());
connect(guiAppInst, &QGuiApplication::screenAdded, this, &MonitorListModel::screenAdded);
@ -70,6 +75,7 @@ QHash<int, QByteArray> MonitorListModel::roleNames() const
{
static const QHash<int, QByteArray> roles {
{ 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::Geometry), "m_geometry" },
{ static_cast<int>(MonitorRole::PreviewImage), "m_previewImage" },
@ -110,6 +116,8 @@ QVariant MonitorListModel::data(const QModelIndex& index, int role) const
switch (roleEnum) {
case MonitorRole::AppID:
return m_monitorList.at(row).m_appID;
case MonitorRole::AppState:
return QVariant::fromValue(m_monitorList.at(row).m_appState);
case MonitorRole::Index:
return m_monitorList.at(row).m_index;
case MonitorRole::Geometry:
@ -267,6 +275,10 @@ bool MonitorListModel::setData(const QModelIndex& index, const QVariant& value,
m_monitorList[index.column()].m_appID = value.toString();
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)) {
m_monitorList[index.column()].m_installedType = static_cast<ContentTypes::InstalledType>(value.toInt());
emit dataChanged(index, index, { role });

View File

@ -2,6 +2,7 @@
#include "ScreenPlay/screenplaymanager.h"
#include "ScreenPlayUtil/util.h"
#include "core/qcorothread.h"
#include <QScopeGuard>
namespace ScreenPlay {
@ -27,6 +28,10 @@ ScreenPlayManager::ScreenPlayManager(
QObject::connect(m_server.get(), &QLocalServer::newConnection, this, &ScreenPlayManager::newConnection);
QObject::connect(&m_screenPlayTimelineManager, &ScreenPlayTimelineManager::requestSaveProfiles, this, &ScreenPlayManager::requestSaveProfiles);
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);
if (!m_server->listen("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:
m_saveLimiter.setInterval(1000);
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> {
if (timelineIndex < 0 || identifier.isEmpty()) {
co_return Result { false };
const QString msg = QString("Invalid timeline index %1 identifier %2").arg(QString::number(timelineIndex), identifier);
Result result;
result.setSuccess(false);
result.setMessage(msg);
co_return result;
}
const bool success = co_await m_screenPlayTimelineManager.setWallpaperAtTimelineIndex(wallpaperData, timelineIndex, identifier);
if (!success) {
qCritical() << "Invalid timeline index or identifier: " << timelineIndex << identifier;
const QString msg = QString("Unable to setWallpaperAtTimelineIndex");
m_screenPlayTimelineManager.printTimelines();
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
// ScreenPlayTimelineManager::checkActiveWallpaperTimeline decide
// if the wallpaper
emit requestSaveProfiles();
// QMetaObject::invokeMethod(this, &ScreenPlayManager::requestSaveProfiles, Qt::QueuedConnection);
co_return Result { success };
}());
}
@ -125,7 +133,7 @@ bool ScreenPlayManager::startWidget(
auto saveToProfile = qScopeGuard([=, this] {
// Do not save on app start
if (saveToProfilesConfigFile) {
emit requestSaveProfiles();
requestSaveProfiles();
}
});
@ -157,11 +165,6 @@ bool ScreenPlayManager::startWidget(
return true;
}
void ScreenPlayManager::setSelectedTimelineIndex(const int selectedTimelineIndex)
{
m_screenPlayTimelineManager.updateMonitorListModelData(selectedTimelineIndex);
}
/*!
\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();
qDebug() << "Task: removeAllWallpaperFromActiveTimlineSections" << success;
if (saveToProfile)
emit requestSaveProfiles();
// QMetaObject::invokeMethod(this, &ScreenPlayManager::requestSaveProfiles, Qt::QueuedConnection);
m_screenPlayTimelineManager.updateMonitorListModelData(selectedTimelineIndex());
co_return Result { success };
}());
}
@ -199,7 +203,7 @@ bool ScreenPlayManager::removeAllRunningWidgets(bool saveToProfile)
}
if (saveToProfile)
emit requestSaveProfiles();
requestSaveProfiles();
return true;
}
@ -211,12 +215,16 @@ bool ScreenPlayManager::removeAllRunningWidgets(bool saveToProfile)
*/
QCoro::QmlTask ScreenPlayManager::removeWallpaperAt(int timelineIndex, QString timelineIdentifier, int monitorIndex)
{
qInfo() << "this: " << this;
return QCoro::QmlTask([this, timelineIndex, timelineIdentifier, monitorIndex]() -> QCoro::Task<Result> {
// call with coro
const bool success = co_await m_screenPlayTimelineManager.removeWallpaperAt(timelineIndex, timelineIdentifier, monitorIndex);
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 };
}());
}
@ -331,6 +339,7 @@ QCoro::QmlTask ScreenPlayManager::removeAllTimlineSections()
qDebug() << "Task: removeAllTimlineSections" << success;
// emit requestSaveProfiles();
// removeAllRunningWallpapers();
// QMetaObject::invokeMethod(this, &ScreenPlayManager::requestSaveProfiles, Qt::QueuedConnection);
co_return Result { success };
}());
}
@ -338,7 +347,7 @@ QCoro::QmlTask ScreenPlayManager::removeAllTimlineSections()
bool ScreenPlayManager::removeTimelineAt(const int index)
{
const bool success = m_screenPlayTimelineManager.removeTimelineAt(index);
emit requestSaveProfiles();
requestSaveProfiles();
return success;
}
/*!
@ -426,52 +435,6 @@ void ScreenPlayManager::setActiveWidgetsCounter(int 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.
*/
@ -536,6 +499,11 @@ int ScreenPlayManager::activeTimelineIndex()
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
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;
}
void ScreenPlayManager::setSelectedTimelineIndex(int selectedTimelineIndex)
{
// if (m_selectedTimelineIndex == selectedTimelineIndex)
// return;
m_selectedTimelineIndex = selectedTimelineIndex;
emit selectedTimelineIndexChanged(m_selectedTimelineIndex);
}
}
#include "moc_screenplaymanager.cpp"

View File

@ -7,6 +7,7 @@
#include <QStringList>
#include <iostream>
#include <ranges>
#include <unordered_set>
namespace ScreenPlay {
@ -94,6 +95,9 @@ bool ScreenPlayTimelineManager::addTimelineFromSettings(const QJsonObject& timel
// TODO check license
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::activeWallpaperCountChanged, this, &ScreenPlayTimelineManager::activeWallpaperCountChanged);
newTimelineSection->startTime = startTime;
@ -181,6 +185,10 @@ void ScreenPlayTimelineManager::checkActiveWallpaperTimeline()
if (currentTimeline != activeTimeline) {
activeTimeline->deactivateTimeline();
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)
{
if (m_wallpaperTimelineSectionsList.isEmpty()) {
qCritical() << "No m_wallpaperTimelineSectionsList is empty";
return;
}
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()) {
qCritical() << "No selectedTimelineIndex found" << selectedTimelineIndex;
return;
}
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) {
// One wallpaper can span across multiple monitors
bool ok;
const int monitorIndex = m_monitorListModel->data(m_monitorListModel->index(i), (int)MonitorListModel::MonitorRole::Index).toInt(&ok);
if (!ok) {
qCritical() << "Invalid monitor index at: " << i;
return;
}
for (const auto& wallpaper : timeline->wallpaperDataList) {
if (wallpaper.monitors.contains(monitorIndex)) {
const auto previewImg = wallpaper.absolutePath + "/" + wallpaper.previewImage;
const auto mondelIndex = m_monitorListModel->index(0, monitorIndex);
m_monitorListModel->setData(mondelIndex, previewImg, (int)MonitorListModel::MonitorRole::PreviewImage);
// TODO
m_monitorListModel->setData(mondelIndex, "dummy", (int)MonitorListModel::MonitorRole::AppID);
m_monitorListModel->setData(mondelIndex, (int)wallpaper.type, (int)MonitorListModel::MonitorRole::InstalledType);
break;
const auto modelIndex = m_monitorListModel->index(0, monitorIndex);
if (activeMonitors.find(monitorIndex) != activeMonitors.end()) {
// Monitor has an active wallpaper
for (const auto& activeWallpaper : timeline->activeWallpaperList) {
if (activeWallpaper->monitors().contains(monitorIndex)) {
const auto previewImg = activeWallpaper->absolutePath() + "/" + activeWallpaper->previewImage();
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)
{
m_globalVariables = globalVariables;
@ -368,7 +392,7 @@ bool ScreenPlayTimelineManager::addTimelineAt(const int index, const float relat
updateIndices();
printTimelines();
emit requestSaveProfiles();
// emit requestSaveProfiles();
return true;
}
@ -421,8 +445,10 @@ QCoro::Task<bool> ScreenPlayTimelineManager::removeWallpaperAt(const int timelin
});
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;
}
const bool success = co_await sectionOpt.value()->removeWallpaper(monitorIndex);
@ -530,13 +556,19 @@ QCoro::Task<bool> ScreenPlayTimelineManager::setWallpaperAtTimelineIndex(
*it = wallpaperData;
// TODO: Do not replace but
co_await timelineSection->deactivateTimeline();
timelineSection->activateTimeline();
} else {
// IMPORTANT: Append the new wallpaper data,
// but do not start it! The selected timelineSection
// is not always be the currently running.
// Besides for this we have m_contentTimer checkActiveWallpaperTimeline()
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;
@ -572,4 +604,17 @@ QJsonArray ScreenPlayTimelineManager::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()
{
setState(ScreenPlayEnums::AppState::Closing);
qInfo() << "Close wallpaper with appID:" << m_appID;
m_pingAliveTimer.stop(); // Stop the timer when closing
// When the wallpaper never connected, this is invalid
if (!m_connection) {
qCritical() << "Cannot request quit, wallpaper never connected!";
setState(ScreenPlayEnums::AppState::Inactive);
return;
}
if (!m_connection->close()) {
qCritical() << "Cannot close wallpaper!";
setState(ScreenPlayEnums::AppState::Inactive);
return;
}
m_isExiting = true;
// The state will be set to Inactive in the disconnected callback
}
/*!
\brief Prints the exit code if != 0.
*/
void ScreenPlayWallpaper::processExit(int exitCode, QProcess::ExitStatus exitStatus)
{
if (exitCode != 0)
qWarning() << "WARNING EXIT CODE: " << exitCode << exitStatus;
setState(ScreenPlay::ScreenPlayEnums::AppState::Inactive);
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)
{
setState(ScreenPlay::ScreenPlayEnums::AppState::Inactive);
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.
*/
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;
}
if (!m_connection) {
qWarning() << "Cannot set value for unconnected wallpaper!";
@ -223,6 +236,16 @@ bool ScreenPlayWallpaper::setWallpaperValue(const QString& key, const QString& v
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()
{
return m_wallpaperData;
@ -237,11 +260,15 @@ void ScreenPlayWallpaper::setSDKConnection(std::unique_ptr<SDKConnection> connec
m_connection = std::move(connection);
qInfo() << "[4/4] SDKConnection (Wallpaper) saved!";
setIsConnected(true);
setState(ScreenPlayEnums::AppState::Active);
QObject::connect(m_connection.get(), &SDKConnection::disconnected, this, [this]() {
setIsConnected(false);
setState(ScreenPlayEnums::AppState::Inactive);
m_pingAliveTimer.stop(); // Stop the timer when disconnected
qInfo() << "Wallpaper:" << m_connection->appID() << "disconnected";
});
QTimer::singleShot(1000, this, [this]() {
if (playbackRate() != 1.0) {
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]() {
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);
});
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
QObject::connect(m_connection.get(), &SDKConnection::pingAliveReceived, this, [this]() {
m_pingAliveTimer.stop();
m_pingAliveTimer.start(GlobalVariables::contentPingAliveIntervalMS);
if (state() == ScreenPlayEnums::AppState::Active) {
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()) {
qInfo() << "running:" << running.value();
} else {
qInfo() << "INVALID PID:" << m_processID;
if (running.has_value()) {
// qInfo() << "running:" << running.value();
} else {
qInfo() << "INVALID PID:" << m_processID;
}
}
});
}
@ -276,9 +306,10 @@ bool ScreenPlayWallpaper::replace(
const WallpaperData wallpaperData,
const bool checkWallpaperVisible)
{
if (m_isExiting)
if (state() != ScreenPlayEnums::AppState::Active) {
qWarning() << "Cannot replace inactive or closing wallpaper!";
return false;
}
if (!m_connection) {
qWarning() << "Cannot replace for unconnected wallpaper!";
@ -300,7 +331,6 @@ bool ScreenPlayWallpaper::replace(
emit requestSave();
return success;
}
}
#include "moc_screenplaywallpaper.cpp"

View File

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

View File

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

View File

@ -23,6 +23,7 @@ set(QML
qml/Dialogs/CriticalError.qml
qml/Dialogs/MonitorConfiguration.qml
qml/Dialogs/SteamNotAvailable.qml
qml/ErrorPopup.qml
qml/FileDropAnimation.qml
qml/FileSelector.qml
qml/Grow.qml
@ -30,11 +31,13 @@ set(QML
qml/Headline.qml
qml/HeadlineSection.qml
qml/ImageSelector.qml
qml/InstantPopup.js
qml/LabelSlider.qml
qml/LicenseSelector.qml
qml/ModalBackgroundBlur.qml
qml/MouseHoverBlocker.qml
qml/Popup.qml
qml/RainbowGradient.qml
qml/RippleEffect.qml
qml/Shake.qml
qml/Tag.qml
@ -57,6 +60,7 @@ set(HEADER
inc/public/ScreenPlayUtil/archive.h
inc/public/ScreenPlayUtil/contenttypes.h
inc/public/ScreenPlayUtil/exitcodes.h
inc/public/ScreenPlayUtil/globalenums.h
inc/public/ScreenPlayUtil/HelpersCommon.h
inc/public/ScreenPlayUtil/ListPropertyHelper.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
qml/Background.qml
qml/Forum.qml
qml/InstalledItem.qml
qml/InstalledItemImage.qml
qml/Navigation.qml
qml/PopupOffline.qml
qml/ScreenPlayItem.qml
qml/ScreenPlayItemImage.qml
qml/Sidebar.qml
qml/SteamProfile.qml
qml/SteamWorkshop.qml

View File

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

View File

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

View File

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