diff --git a/ScreenPlay/CMakeLists.txt b/ScreenPlay/CMakeLists.txt index 6c8f3ac4..77609460 100644 --- a/ScreenPlay/CMakeLists.txt +++ b/ScreenPlay/CMakeLists.txt @@ -12,7 +12,7 @@ set(SOURCES # cmake-format: sort src/wallpaperdata.cpp src/wallpapertimelinesection.cpp - src/screenplaytimeline.cpp + src/screenplaytimelinemanager.cpp src/app.cpp src/applicationengine.cpp src/create.cpp @@ -34,7 +34,7 @@ set(HEADER # cmake-format: sort inc/public/ScreenPlay/wallpaperdata.h inc/public/ScreenPlay/wallpapertimelinesection.h - inc/public/ScreenPlay/screenplaytimeline.h + inc/public/ScreenPlay/screenplaytimelinemanager.h inc/public/ScreenPlay/app.h inc/public/ScreenPlay/applicationengine.h inc/public/ScreenPlay/create.h diff --git a/ScreenPlay/inc/public/ScreenPlay/create.h b/ScreenPlay/inc/public/ScreenPlay/create.h index 6d7c539b..d04d5db3 100644 --- a/ScreenPlay/inc/public/ScreenPlay/create.h +++ b/ScreenPlay/inc/public/ScreenPlay/create.h @@ -2,31 +2,16 @@ #pragma once -#include -#include -#include #include #include -#include -#include -#include -#include #include -#include #include -#include #include -#include -#include -#include -#include -#include - #include #include "ScreenPlay/createimportstates.h" -#include "ScreenPlay/createimportvideo.h" #include "ScreenPlay/globalvariables.h" +#include "ScreenPlayUtil/contenttypes.h" namespace ScreenPlay { @@ -40,9 +25,9 @@ class Create : public QObject { Q_PROPERTY(QString ffmpegOutput READ ffmpegOutput WRITE appendFfmpegOutput NOTIFY ffmpegOutputChanged) public: - explicit Create(const std::shared_ptr& globalVariables); + explicit Create(const std::shared_ptr& globalVariables, QObject* parent = nullptr); - Create(); + Create(QObject* parent = nullptr); Q_INVOKABLE void cancel(); diff --git a/ScreenPlay/inc/public/ScreenPlay/globalvariables.h b/ScreenPlay/inc/public/ScreenPlay/globalvariables.h index a6b34164..025b611a 100644 --- a/ScreenPlay/inc/public/ScreenPlay/globalvariables.h +++ b/ScreenPlay/inc/public/ScreenPlay/globalvariables.h @@ -2,14 +2,9 @@ #pragma once -#include #include #include -#include #include -#include - -#include namespace ScreenPlay { diff --git a/ScreenPlay/inc/public/ScreenPlay/installedlistfilter.h b/ScreenPlay/inc/public/ScreenPlay/installedlistfilter.h index 36c6ce9a..fe598332 100644 --- a/ScreenPlay/inc/public/ScreenPlay/installedlistfilter.h +++ b/ScreenPlay/inc/public/ScreenPlay/installedlistfilter.h @@ -2,11 +2,9 @@ #pragma once -#include #include #include -#include "ScreenPlay/globalvariables.h" #include "ScreenPlay/installedlistmodel.h" namespace ScreenPlay { diff --git a/ScreenPlay/inc/public/ScreenPlay/installedlistmodel.h b/ScreenPlay/inc/public/ScreenPlay/installedlistmodel.h index 56cef13a..ffe9e34d 100644 --- a/ScreenPlay/inc/public/ScreenPlay/installedlistmodel.h +++ b/ScreenPlay/inc/public/ScreenPlay/installedlistmodel.h @@ -4,30 +4,18 @@ #include #include -#include -#include #include #include -#include #include -#include -#include #include -#include -#include -#include -#include #include -#include #include -#include +#include #include "ScreenPlay/globalvariables.h" #include "ScreenPlay/settings.h" #include "ScreenPlayUtil/projectfile.h" -#include - namespace ScreenPlay { class InstalledListModel : public QAbstractListModel { @@ -67,9 +55,9 @@ public: { return m_count; } + Q_INVOKABLE QVariantMap get(const QString& folderName) const; public slots: - QVariantMap get(const QString& folderName) const; void loadInstalledContent(); void append(const QString& projectJsonFilePath); diff --git a/ScreenPlay/inc/public/ScreenPlay/monitorlistmodel.h b/ScreenPlay/inc/public/ScreenPlay/monitorlistmodel.h index f003e5b5..91076c50 100644 --- a/ScreenPlay/inc/public/ScreenPlay/monitorlistmodel.h +++ b/ScreenPlay/inc/public/ScreenPlay/monitorlistmodel.h @@ -4,22 +4,16 @@ #include -#include #include #include #include #include #include - -#include "ScreenPlay/screenplaywallpaper.h" -#include "ScreenPlay/wallpapertimelinesection.h" - -#ifdef Q_OS_WIN -#include -#endif #include #include +#include "ScreenPlay/wallpapertimelinesection.h" + namespace ScreenPlay { struct Monitor { diff --git a/ScreenPlay/inc/public/ScreenPlay/profilelistmodel.h b/ScreenPlay/inc/public/ScreenPlay/profilelistmodel.h index 55f7c234..8fb91f5d 100644 --- a/ScreenPlay/inc/public/ScreenPlay/profilelistmodel.h +++ b/ScreenPlay/inc/public/ScreenPlay/profilelistmodel.h @@ -3,19 +3,13 @@ #pragma once #include -#include -#include -#include -#include #include -#include #include +#include #include "ScreenPlay/globalvariables.h" #include "ScreenPlay/profile.h" -#include - namespace ScreenPlay { struct Profile; diff --git a/ScreenPlay/inc/public/ScreenPlay/projectsettingslistmodel.h b/ScreenPlay/inc/public/ScreenPlay/projectsettingslistmodel.h index 061edcb9..1e79f13e 100644 --- a/ScreenPlay/inc/public/ScreenPlay/projectsettingslistmodel.h +++ b/ScreenPlay/inc/public/ScreenPlay/projectsettingslistmodel.h @@ -1,18 +1,11 @@ // SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only #pragma once - +#include "ScreenPlayUtil/contenttypes.h" #include -#include -#include -#include -#include -#include #include #include -#include "ScreenPlayUtil/util.h" - namespace ScreenPlay { struct SettingsItem { diff --git a/ScreenPlay/inc/public/ScreenPlay/screenplaymanager.h b/ScreenPlay/inc/public/ScreenPlay/screenplaymanager.h index bbce6ef1..5e09a60e 100644 --- a/ScreenPlay/inc/public/ScreenPlay/screenplaymanager.h +++ b/ScreenPlay/inc/public/ScreenPlay/screenplaymanager.h @@ -2,21 +2,20 @@ #pragma once +#include #include #include -#include -#include - -#include "ScreenPlay/screenplaytimeline.h" -#include "ScreenPlayUtil/util.h" -#include "globalvariables.h" -#include "monitorlistmodel.h" -#include "projectsettingslistmodel.h" -#include "screenplaywallpaper.h" -#include "screenplaywidget.h" -#include "settings.h" #include +#include "ScreenPlay/globalvariables.h" +#include "ScreenPlay/monitorlistmodel.h" +#include "ScreenPlay/projectsettingslistmodel.h" +#include "ScreenPlay/screenplaytimelinemanager.h" +#include "ScreenPlay/screenplaywallpaper.h" +#include "ScreenPlay/screenplaywidget.h" +#include "ScreenPlay/settings.h" +#include "ScreenPlayUtil/util.h" + namespace ScreenPlay { @@ -37,9 +36,6 @@ public: const std::shared_ptr& mlm, const std::shared_ptr& settings); - int activeWallpaperCounter() const { return m_activeWallpaperCounter; } - int activeWidgetsCounter() const { return m_activeWidgetsCounter; } - std::shared_ptr startWallpaper( WallpaperData wallpaperData, const bool saveToProfilesConfigFile); @@ -55,14 +51,11 @@ public: const QString identifier, const float relativePosition, QString positionTimeString); - - Q_INVOKABLE QString getTimeString(double relativeLinePosition); - Q_INVOKABLE bool addTimelineAt( const int index, const float reltiaveLinePosition, QString identifier); - Q_INVOKABLE void removeAllTimlineSections(); + Q_INVOKABLE QCoro::QmlTask removeAllTimlineSections(); Q_INVOKABLE bool removeTimelineAt(const int index); Q_INVOKABLE QJsonArray initialSectionsList(); Q_INVOKABLE bool setWallpaperAtTimelineIndex( @@ -89,7 +82,11 @@ public: 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); - signals: + + int activeWallpaperCounter() const { return m_activeWallpaperCounter; } + int activeWidgetsCounter() const { return m_activeWidgetsCounter; } + +signals: void activeWallpaperCounterChanged(int activeWallpaperCounter); void activeWidgetsCounterChanged(int activeWidgetsCounter); void monitorConfigurationChanged(); @@ -103,21 +100,16 @@ public: private slots: bool saveProfiles(); - void checkActiveWallpaperTimeline(); void newConnection(); void setActiveWallpaperCounter(int activeWallpaperCounter); void setActiveWidgetsCounter(int activeWidgetsCounter); private: - void printTimelines(); bool loadProfiles(); - void updateQmlTimelines(); - void updateIndices(); bool checkIsAnotherScreenPlayInstanceRunning(); bool removeWallpaper(const QString& appID); bool removeWidget(const QString& appID); - void activateNewTimeline(); bool loadWidgetConfig(const QJsonObject& widget); std::shared_ptr m_globalVariables; @@ -126,13 +118,12 @@ private: std::unique_ptr m_server; QVector> m_screenPlayWidgets; std::vector> m_unconnectedClients; - ScreenPlayTimeline m_screenPlayTimeline; + ScreenPlayTimelineManager m_screenPlayTimelineManager; int m_activeWallpaperCounter { 0 }; int m_activeWidgetsCounter { 0 }; QTimer m_saveLimiter; - QTimer m_contentTimer; Util m_util; diff --git a/ScreenPlay/inc/public/ScreenPlay/screenplaytimeline.h b/ScreenPlay/inc/public/ScreenPlay/screenplaytimeline.h deleted file mode 100644 index 24e8c13f..00000000 --- a/ScreenPlay/inc/public/ScreenPlay/screenplaytimeline.h +++ /dev/null @@ -1,37 +0,0 @@ -// SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only - -#pragma once - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ScreenPlay/wallpapertimelinesection.h" - -namespace ScreenPlay { - - -struct ScreenPlayTimeline{ - - - float calculateRelativePosition(const QTime& endTime); - - std::optional> loadTimelineWallpaperConfig(const QJsonObject& timelineObj); - std::shared_ptr findActiveWallpaperTimelineSection(); - std::optional> activeWallpaperSectionByAppID(const QString& appID); - std::shared_ptr getCurrentTimeline(); - - - QVector> m_wallpaperTimelineSectionsList; - - // We use a24 hour system - const QString m_timelineTimeFormat = "hh:mm:ss"; -}; - -} diff --git a/ScreenPlay/inc/public/ScreenPlay/screenplaytimelinemanager.h b/ScreenPlay/inc/public/ScreenPlay/screenplaytimelinemanager.h new file mode 100644 index 00000000..0302d610 --- /dev/null +++ b/ScreenPlay/inc/public/ScreenPlay/screenplaytimelinemanager.h @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only + +#pragma once + +#include +#include +#include + +#include "ScreenPlay/wallpapertimelinesection.h" + +namespace ScreenPlay { + +class ScreenPlayTimelineManager : public QObject { + Q_OBJECT + +public: + explicit ScreenPlayTimelineManager(QObject* parent = nullptr); + + std::optional> activeWallpaperSectionByAppID(const QString& appID); + std::shared_ptr findActiveWallpaperTimelineSection(); + std::shared_ptr findTimelineForCurrentTime(); + bool addTimelineFromSettings(const QJsonObject& timelineObj); + bool deactivateCurrentTimeline(); + bool moveTimelineAt(const int index, const QString identifier, const float relativePosition, QString positionTimeString); + bool startTimeline(); + bool addTimelineAt(const int index, const float reltiaveLinePosition, QString identifier); + bool removeTimelineAt(const int index); + QCoro::Task removeAllTimlineSections(); + void updateIndices(); + void printTimelines(); + bool setWallpaperAtTimelineIndex(WallpaperData wallpaperData, + const int timelineIndex, + const QString& identifier); + QJsonArray initialSectionsList(); + QJsonArray timelineWallpaperList(); + void setGlobalVariables(const std::shared_ptr& globalVariables); + void setSettings(const std::shared_ptr& settings); + void startupFirstTimeline(); +private slots: + void checkActiveWallpaperTimeline(); + +signals: + void requestSaveProfiles(); + +private: + QVector> m_wallpaperTimelineSectionsList; + // We use a 24 hour system + const QString m_timelineTimeFormat = "hh:mm:ss"; + QTimer m_contentTimer; + std::shared_ptr m_globalVariables; + std::shared_ptr m_settings; +}; +} diff --git a/ScreenPlay/inc/public/ScreenPlay/screenplaywallpaper.h b/ScreenPlay/inc/public/ScreenPlay/screenplaywallpaper.h index fb816b38..d6dfbcd5 100644 --- a/ScreenPlay/inc/public/ScreenPlay/screenplaywallpaper.h +++ b/ScreenPlay/inc/public/ScreenPlay/screenplaywallpaper.h @@ -2,14 +2,12 @@ #pragma once -#include -#include -#include #include #include #include #include #include +#include #include #include "ScreenPlay/globalvariables.h" diff --git a/ScreenPlay/inc/public/ScreenPlay/screenplaywidget.h b/ScreenPlay/inc/public/ScreenPlay/screenplaywidget.h index 9cf55a65..7df0e13f 100644 --- a/ScreenPlay/inc/public/ScreenPlay/screenplaywidget.h +++ b/ScreenPlay/inc/public/ScreenPlay/screenplaywidget.h @@ -2,21 +2,19 @@ #pragma once -#include -#include #include #include #include #include #include +#include +#include #include "ScreenPlay/globalvariables.h" #include "ScreenPlay/projectsettingslistmodel.h" #include "ScreenPlay/sdkconnection.h" #include "ScreenPlayUtil/processmanager.h" -#include - namespace ScreenPlay { class ScreenPlayWidget : public QObject { diff --git a/ScreenPlay/inc/public/ScreenPlay/sdkconnection.h b/ScreenPlay/inc/public/ScreenPlay/sdkconnection.h index 88bb4787..71aa17d1 100644 --- a/ScreenPlay/inc/public/ScreenPlay/sdkconnection.h +++ b/ScreenPlay/inc/public/ScreenPlay/sdkconnection.h @@ -2,21 +2,11 @@ #pragma once -#include #include -#include -#include #include #include #include -#include #include -#include - -#include "ScreenPlay/globalvariables.h" -#include "ScreenPlayUtil/util.h" - -#include namespace ScreenPlay { diff --git a/ScreenPlay/inc/public/ScreenPlay/settings.h b/ScreenPlay/inc/public/ScreenPlay/settings.h index 86a5f1bc..a0b0921f 100644 --- a/ScreenPlay/inc/public/ScreenPlay/settings.h +++ b/ScreenPlay/inc/public/ScreenPlay/settings.h @@ -2,41 +2,16 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include #include -#include -#include -#include -#include #include -#include #include -#include -#include -#include -#include +#include #include -#include #include -#include -#include #include "ScreenPlay/globalvariables.h" -#include "ScreenPlayUtil/util.h" - +#include "ScreenPlayUtil/contenttypes.h" #include -#include namespace ScreenPlay { class ActiveProfile; diff --git a/ScreenPlay/inc/public/ScreenPlay/wallpapertimelinesection.h b/ScreenPlay/inc/public/ScreenPlay/wallpapertimelinesection.h index d1e20b94..af913874 100644 --- a/ScreenPlay/inc/public/ScreenPlay/wallpapertimelinesection.h +++ b/ScreenPlay/inc/public/ScreenPlay/wallpapertimelinesection.h @@ -1,16 +1,15 @@ // SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only #pragma once - -#include -#include -#include +#include +#include #include #include -#include #include -#include +#include +#include "ScreenPlay/globalvariables.h" +#include "ScreenPlay/settings.h" #include "ScreenPlay/wallpaperdata.h" namespace ScreenPlay { @@ -18,13 +17,20 @@ class ScreenPlayWallpaper; // Represents one line in the UI. ScreenPlayManager has a list of // WallpaperTimeline. Only the active timeline section has // a filled vector of ScreenPlayWallpaper -struct WallpaperTimelineSection { - // Is active is needed as an additional flag during switching. - // When timeline A is no longer in the time range, then we can - // use this flag to know that it was the last active timeline and - // remove all active wallpaper. - bool isActive = false; - +class WallpaperTimelineSection : public QObject { + Q_OBJECT + QML_ELEMENT + QML_UNCREATABLE("") + Q_CLASSINFO("RegisterEnumClassesUnscoped", "false") +public: + enum class Status { + Inactive, + Starting, + Closing, + Active, + }; + Q_ENUM(Status) + Status status = Status::Inactive; QString identifier; int index = 0; // Needed to check float relativePosition = 0.0f; @@ -33,49 +39,21 @@ struct WallpaperTimelineSection { // Data from the profiles.json that we need when we // enable this section of the pipeline. We keep a copy // here when this timeline needs to become active - std::vector wallpaperData; + std::vector wallpaperDataList; // All active wallpaper. std::vector> activeWallpaperList; - bool close(); - + std::shared_ptr globalVariables; + std::shared_ptr settings; // Check if currentTime falls within the timeline section - bool containsTime(const QTime& time) const - { - if (endTime < startTime) { // Timeline spans midnight - return (time >= startTime || time < endTime); - } else { - return (time >= startTime && time < endTime); - } - } + bool containsTime(const QTime& time) const; - QJsonObject serialize() const - { - QJsonObject data; - data.insert("isActive", isActive); - data.insert("identifier", identifier); - data.insert("index", index); - data.insert("relativePosition", relativePosition); - data.insert("startTime", startTime.toString()); - data.insert("endTime", endTime.toString()); + QJsonObject serialize() const; - // Serialize vector - QJsonArray wallpaperDataArray; - for (const auto& wallpaper : wallpaperData) { - QJsonObject wallpaperObject = wallpaper.serialize(); // Assuming WallpaperData has a serialize method - wallpaperDataArray.append(wallpaperObject); - } - data.insert("wallpaperData", wallpaperDataArray); + bool activateTimeline(); + QCoro::Task deactivateTimeline(); - // Serialize vector> - // QJsonArray activeWallpaperArray; - // for (const auto& wallpaper : activeWallpaperList) { - // QJsonObject wallpaperObject = wallpaper->serialize(); // Assuming ScreenPlayWallpaper has a serialize method - // activeWallpaperArray.append(wallpaperObject); - // } - // data.insert("activeWallpaperList", activeWallpaperArray); - - return data; - } +signals: + void requestSaveProfiles(); }; } diff --git a/ScreenPlay/inc/public/ScreenPlay/wizards.h b/ScreenPlay/inc/public/ScreenPlay/wizards.h index ef852c68..685dea85 100644 --- a/ScreenPlay/inc/public/ScreenPlay/wizards.h +++ b/ScreenPlay/inc/public/ScreenPlay/wizards.h @@ -2,41 +2,24 @@ #pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ScreenPlay/CMakeVariables.h" #include "ScreenPlay/globalvariables.h" #include "ScreenPlayUtil/util.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include "qcorotask.h" #include "qml/qcoroqml.h" #include "qml/qcoroqmltask.h" -#include -#include - namespace ScreenPlay { class Wizards : public QObject { diff --git a/ScreenPlay/qml/Components/Timeline.qml b/ScreenPlay/qml/Components/Timeline.qml index 3a43c4e8..e519f5a1 100644 --- a/ScreenPlay/qml/Components/Timeline.qml +++ b/ScreenPlay/qml/Components/Timeline.qml @@ -18,17 +18,19 @@ Control { property int length: timeLine.sectionsList.length function getActiveTimeline() { - return timeLine.sectionsList[root.activeTimelineIndex]; + return timeLine.sectionsList[root.activeTimelineIndex] } function removeAll() { - timeLine.removeAll(); + timeLine.removeAll() } function printTimelines() { - print("################# qml:"); + print("################# qml:") for (var i = 0; i < timeLine.sectionsList.length; i++) { - print(timeLine.sectionsList[i].index, timeLine.sectionsList[i].identifier, timeLine.sectionsList[i].relativeLinePosition); + print(timeLine.sectionsList[i].index, + timeLine.sectionsList[i].identifier, + timeLine.sectionsList[i].relativeLinePosition) } } @@ -38,7 +40,8 @@ Control { property string identifier property int index: 0 property real relativeLinePosition: lineHandle.linePosition - onRelativeLinePositionChanged: print("relativelinepos: ", relativeLinePosition) + onRelativeLinePositionChanged: print("relativelinepos: ", + relativeLinePosition) property LineHandle lineHandle property LineIndicator lineIndicator } @@ -52,35 +55,45 @@ Control { onWidthChanged: timeLine.updatePositions() property var initialSectionsList: [] Component.onCompleted: { - let sectionObects = App.screenPlayManager.initialSectionsList(); + let sectionObects = App.screenPlayManager.initialSectionsList() for (let sectionObject in sectionObects) { - initialSectionsList.push(sectionObects[sectionObject]); + initialSectionsList.push(sectionObects[sectionObject]) } initialSectionsList.sort(function (a, b) { - return b.index - a.index; - }); + return b.index - a.index + }) for (let index in initialSectionsList) { - let section = initialSectionsList[index]; - addSection(section.identifier, section.relativePosition); + let section = initialSectionsList[index] + addSection(section.identifier, section.relativePosition) } } function removeAll() { - print("removeAll", timeLine.sectionsList.length); + print("removeAll", timeLine.sectionsList.length) for (var i = 0; i < timeLine.sectionsList.length; i++) { // ORDER is important here! Destory the children first - print("remove index ", i); - let section = timeLine.sectionsList[i]; - section.lineHandle.destroy(); - section.lineIndicator.destroy(); - section.destroy(); + print("remove index ", i) + let section = timeLine.sectionsList[i] + section.lineHandle.destroy() + section.lineIndicator.destroy() + section.destroy() } - timeLine.sectionsList = []; - App.screenPlayManager.removeAllTimlineSections(); - 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); + timeLine.sectionsList = [] + App.screenPlayManager.removeAllTimlineSections().then(result => { + + if (!result.success) { + console.error("removeAllTimlineSections failed") + return + } + + 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) + }) } // IMPORTANT: The new element is always on the left. The first @@ -88,206 +101,215 @@ Control { // user can never delete it. It only gets "pushed" further // to the right, by decreasing its size. function addSection(identifier, stopPosition) { - print("stopPosition", stopPosition); + print("stopPosition", stopPosition) // Make sure to limit float precision - const fixedStopPosition = stopPosition; - print("addSection at: ", fixedStopPosition); + const fixedStopPosition = stopPosition + print("addSection at: ", fixedStopPosition) if (stopPosition < 0 || fixedStopPosition > 1) { - console.error("Invalid position:", fixedStopPosition); - return; + console.error("Invalid position:", fixedStopPosition) + return } let sectionObject = sectionComp.createObject(timeLine, { - "identifier": identifier, - "relativeLinePosition": fixedStopPosition - }); - timeLine.sectionsList.push(sectionObject); + "identifier": identifier, + "relativeLinePosition": fixedStopPosition + }) + timeLine.sectionsList.push(sectionObject) timeLine.sectionsList.sort(function (a, b) { - return a.relativeLinePosition - b.relativeLinePosition; - }); - const index = timeLine.sectionsList.indexOf(sectionObject); - console.log("Addsection:", index); - createSection(index, fixedStopPosition, sectionObject, identifier); - updatePositions(); - return sectionObject; + return a.relativeLinePosition - b.relativeLinePosition + }) + const index = timeLine.sectionsList.indexOf(sectionObject) + console.log("Addsection:", index) + createSection(index, fixedStopPosition, sectionObject, identifier) + updatePositions() + return sectionObject } function createSection(index, stopPosition, section, identifier) { - console.log("Adding at:", index, stopPosition, identifier); + console.log("Adding at:", index, stopPosition, identifier) //console.assert(isFloat(stopPosition)) - let haComponent = Qt.createComponent("LineHandle.qml"); + let haComponent = Qt.createComponent("LineHandle.qml") if (haComponent.status === Component.Error) { - console.assert(haComponent.errorString()); - return; + console.assert(haComponent.errorString()) + return } - section.lineHandle = haComponent.createObject(handleWrapper); - section.lineHandle.lineWidth = timeLine.width; - section.lineHandle.x = Math.round(handleWrapper.width * timeLine.sectionsList[index].relativeLinePosition); - section.lineHandle.y = -section.lineHandle.height / 2; + section.lineHandle = haComponent.createObject(handleWrapper) + section.lineHandle.lineWidth = timeLine.width + section.lineHandle.x = Math.round( + handleWrapper.width * timeLine.sectionsList[index].relativeLinePosition) + section.lineHandle.y = -section.lineHandle.height / 2 // Will be set later - section.lineHandle.lineMinimum = timeLine.x; - section.lineHandle.lineMaximum = timeLine.x; - section.lineHandle.handleMoved.connect(timeLine.onHandleMoved); - let liComponent = Qt.createComponent("LineIndicator.qml"); + section.lineHandle.lineMinimum = timeLine.x + section.lineHandle.lineMaximum = timeLine.x + section.lineHandle.handleMoved.connect(timeLine.onHandleMoved) + let liComponent = Qt.createComponent("LineIndicator.qml") if (liComponent.status === Component.Error) { - console.assert(liComponent.errorString()); - return; + console.assert(liComponent.errorString()) + return } // Set color initially so we do not have a weird color animation at start const lineIndicatorProperties = { "color": getColorAtIndex(index) - }; - section.lineIndicator = liComponent.createObject(lineIndicatorWrapper, lineIndicatorProperties); - section.lineIndicator.height = lineIndicatorWrapper.height; - section.lineIndicator.index = index; - section.lineIndicator.identifier = identifier; - section.lineIndicator.color = getColorAtIndex(index); - section.lineIndicator.remove.connect(timeLine.removeSection); - section.lineIndicator.lineSelected.connect(timeLine.lineIndicatorSelected); + } + section.lineIndicator = liComponent.createObject( + lineIndicatorWrapper, lineIndicatorProperties) + section.lineIndicator.height = lineIndicatorWrapper.height + section.lineIndicator.index = index + section.lineIndicator.identifier = identifier + section.lineIndicator.color = getColorAtIndex(index) + section.lineIndicator.remove.connect(timeLine.removeSection) + section.lineIndicator.lineSelected.connect( + timeLine.lineIndicatorSelected) } function sectionFromHandle(lineHandle) { for (var i = 0; i < timeLine.sectionsList.length; i++) { if (timeLine.sectionsList[i].lineHandle === lineHandle) - return timeLine.sectionsList[i]; + return timeLine.sectionsList[i] } - return null; + return null } function onHandleMoved(lineHandle) { - updatePositions(); - const section = sectionFromHandle(lineHandle); + updatePositions() + const section = sectionFromHandle(lineHandle) if (section === null) { - print(lineHandle.linePosition); - console.error("Unable to match handle to section list"); - return; + print(lineHandle.linePosition) + console.error("Unable to match handle to section list") + return } - App.screenPlayManager.moveTimelineAt(section.index, section.identifier, lineHandle.linePosition, lineHandle.timeString); + App.screenPlayManager.moveTimelineAt(section.index, + section.identifier, + lineHandle.linePosition, + lineHandle.timeString) } function lineIndicatorSelected(activeTimelineIndex) { for (var i = 0; i < timeLine.sectionsList.length; i++) { if (i === activeTimelineIndex) { - timeLine.sectionsList[i].lineIndicator.selected = true; - continue; + timeLine.sectionsList[i].lineIndicator.selected = true + continue } - timeLine.sectionsList[i].lineIndicator.selected = false; + timeLine.sectionsList[i].lineIndicator.selected = false } - root.activeTimelineIndex = activeTimelineIndex; + root.activeTimelineIndex = activeTimelineIndex } // We must update all indexes when removing/adding an element function updateIndicatorIndexes() { - if (timeLine.sectionsList === null || timeLine.sectionsList === undefined) - return; + if (timeLine.sectionsList === null + || timeLine.sectionsList === undefined) + return timeLine.sectionsList.sort(function (a, b) { - return a.relativeLinePosition - b.relativeLinePosition; - }); + return a.relativeLinePosition - b.relativeLinePosition + }) for (var i = 0; i < timeLine.sectionsList.length; i++) { - timeLine.sectionsList[i].index = i; - timeLine.sectionsList[i].lineIndicator.index = i; + timeLine.sectionsList[i].index = i + timeLine.sectionsList[i].lineIndicator.index = i //print("updateIndicatorIndexes:", timeLine.sectionsList[i].index, timeLine.sectionsList[i].relativeLinePosition) } } function removeSection(index) { - print(timeLine.stopPositionList); - print(timeLine.sectionList); - const isLast = index === timeLine.sectionsList.length - 1; + print(timeLine.stopPositionList) + print(timeLine.sectionList) + const isLast = index === timeLine.sectionsList.length - 1 if (isLast) - return; + return // ORDER is important here! First destory the object // and then remove i f - let section = timeLine.sectionsList[index]; - section.lineHandle.destroy(); - section.lineIndicator.destroy(); - section.destroy(); - timeLine.sectionsList.splice(index, 1); - updatePositions(); - App.screenPlayManager.removeTimelineAt(index); + let section = timeLine.sectionsList[index] + section.lineHandle.destroy() + section.lineIndicator.destroy() + section.destroy() + timeLine.sectionsList.splice(index, 1) + updatePositions() + App.screenPlayManager.removeTimelineAt(index) } function updatePositions() { // Iterate through each handle in the 'sectionList' array for (var i = 0; i < timeLine.sectionsList.length; i++) { - let handle = timeLine.sectionsList[i].lineHandle; + let handle = timeLine.sectionsList[i].lineHandle // Determine the minimum position for the current handle - let prevPos; + let prevPos if (i === 0) { // If it's the first handle, its minimum is 0 - prevPos = 0; + prevPos = 0 } else { // Otherwise, it's directly the position of the previous handle - prevPos = timeLine.sectionsList[i - 1].lineHandle.x; + prevPos = timeLine.sectionsList[i - 1].lineHandle.x } // Determine the maximum position for the current handle - let nextPos; + let nextPos if (i === timeLine.sectionsList.length - 1) { // If it's the last handle, its maximum is the width of the line - nextPos = timeLine.width; + nextPos = timeLine.width } else { // Otherwise, it's directly the position of the next handle - nextPos = timeLine.sectionsList[i + 1].lineHandle.x; + nextPos = timeLine.sectionsList[i + 1].lineHandle.x } // Set the determined minimum and maximum positions for the current handle - handle.lineMinimum = prevPos; - handle.lineMaximum = nextPos; + handle.lineMinimum = prevPos + handle.lineMaximum = nextPos //timeLine.sectionsList[i].relativeLinePosition =prevPos / timeLine.width // print("sections: ", i, "prev minimum ",prevPos,"next maximum", nextPos, timeLine.sectionsList[i].relativeLinePosition) } for (var i = 0; i < timeLine.sectionsList.length; i++) { - let section = timeLine.sectionsList[i]; - section.relativeLinePosition = section.lineHandle.linePosition; + let section = timeLine.sectionsList[i] + section.relativeLinePosition = section.lineHandle.linePosition // print(section.relativeLinePosition, section.lineHandle.lineMinimum, section.lineHandle.lineMaximum) } - updateIndicatorPositions(); - updateLastHandle(); - updateIndicatorColor(); - updateIndicatorIndexes(); + updateIndicatorPositions() + updateLastHandle() + updateIndicatorColor() + updateIndicatorIndexes() } function getColorAtIndex(index) { - let i = index; + let i = index // Start from the beginnging again if (index >= timeLine.lineColors.length) { - i = index % timeLine.lineColors.length; + i = index % timeLine.lineColors.length } - return timeLine.lineColors[i]; + return timeLine.lineColors[i] } function updateIndicatorColor() { for (var i = 0; i < timeLine.sectionsList.length; i++) { - let lineIndicator = timeLine.sectionsList[i].lineIndicator; - lineIndicator.color = getColorAtIndex(i); + let lineIndicator = timeLine.sectionsList[i].lineIndicator + lineIndicator.color = getColorAtIndex(i) } } function updateLastHandle() { for (var i = 0; i < timeLine.sectionsList.length; i++) { - timeLine.sectionsList[i].lineHandle.isLast = i === timeLine.sectionsList.length - 1; - timeLine.sectionsList[i].lineIndicator.isLast = i === timeLine.sectionsList.length - 1; + timeLine.sectionsList[i].lineHandle.isLast = i === timeLine.sectionsList.length - 1 + timeLine.sectionsList[i].lineIndicator.isLast = i + === timeLine.sectionsList.length - 1 } } function updateIndicatorPositions() { for (var i = 0; i < timeLine.sectionsList.length; i++) { - const lineIndicator = timeLine.sectionsList[i].lineIndicator; + const lineIndicator = timeLine.sectionsList[i].lineIndicator //print(i, lineIndicator.x, lineIndicator.width, timeLine.sectionsList[i].relativeLinePosition) - const handle = timeLine.sectionsList[i].lineHandle; - lineIndicator.x = handle.dragHandler.xAxis.minimum; - lineIndicator.width = (handle.linePosition * handle.lineWidth).toFixed(2) - lineIndicator.x; + const handle = timeLine.sectionsList[i].lineHandle + lineIndicator.x = handle.dragHandler.xAxis.minimum + lineIndicator.width = (handle.linePosition * handle.lineWidth).toFixed( + 2) - lineIndicator.x } } // https://stackoverflow.com/a/3885844 function isFloat(n) { - return n === +n && n !== (n | 0); + return n === +n && n !== (n | 0) } Rectangle { @@ -310,10 +332,13 @@ Control { color: Material.color(Material.BlueGrey) width: 2 height: 30 - y: (addHandleWrapper.height - height) / 2 // Vertically center within addHandleWrapper + y: (addHandleWrapper.height - height) + / 2 // Vertically center within addHandleWrapper property int totalSeconds: 86400 // Total seconds in a day - property int currentSeconds: (new Date().getHours() * 3600) + (new Date().getMinutes() * 60) + new Date().getSeconds() + property int currentSeconds: (new Date().getHours( + ) * 3600) + (new Date().getMinutes( + ) * 60) + new Date().getSeconds() x: addHandleWrapper.width * (currentSeconds / totalSeconds) @@ -322,9 +347,15 @@ Control { repeat: true running: true onTriggered: { - currentTimeIndicator.currentSeconds = (new Date().getHours() * 3600) + (new Date().getMinutes() * 60) + new Date().getSeconds(); - currentTimeIndicator.x = addHandleWrapper.width * (currentTimeIndicator.currentSeconds / currentTimeIndicator.totalSeconds); - currentTimeText.text = Qt.formatTime(new Date(), "hh:mm:ss"); + currentTimeIndicator.currentSeconds + = (new Date().getHours( + ) * 3600) + (new Date().getMinutes( + ) * 60) + new Date().getSeconds( + ) + currentTimeIndicator.x = addHandleWrapper.width + * (currentTimeIndicator.currentSeconds / currentTimeIndicator.totalSeconds) + currentTimeText.text = Qt.formatTime(new Date(), + "hh:mm:ss") } } } @@ -372,11 +403,15 @@ Control { ToolButton { text: "➕" onClicked: { - const p = this.x / timeLine.width; - const position = p.toFixed(4); - const identifier = App.util.generateRandomString(4); - const sectionObject = timeLine.addSection(identifier, position); - App.screenPlayManager.addTimelineAt(sectionObject.index, sectionObject.relativeLinePosition, sectionObject.identifier); + const p = this.x / timeLine.width + const position = p.toFixed(4) + const identifier = App.util.generateRandomString(4) + const sectionObject = timeLine.addSection(identifier, + position) + App.screenPlayManager.addTimelineAt( + sectionObject.index, + sectionObject.relativeLinePosition, + sectionObject.identifier) } x: hoverHandler.point.position.x - width * .5 diff --git a/ScreenPlay/src/app.cpp b/ScreenPlay/src/app.cpp index 32625e27..a71187f6 100644 --- a/ScreenPlay/src/app.cpp +++ b/ScreenPlay/src/app.cpp @@ -120,12 +120,13 @@ void App::init() // Must be called last to display a error message on startup by the qml engine m_screenPlayManager->init(m_globalVariables, m_monitorListModel, m_settings); - QObject::connect( - m_monitorListModel.get(), - &MonitorListModel::monitorConfigurationChanged, - m_screenPlayManager.get(), [this]() { - m_screenPlayManager->removeAllWallpapers(true); - }); + // TODO + // QObject::connect( + // m_monitorListModel.get(), + // &MonitorListModel::monitorConfigurationChanged, + // m_screenPlayManager.get(), [this]() { + // m_screenPlayManager->removeAllWallpapers(true); + // }); } QString App::version() const diff --git a/ScreenPlay/src/create.cpp b/ScreenPlay/src/create.cpp index f2041b06..125e054a 100644 --- a/ScreenPlay/src/create.cpp +++ b/ScreenPlay/src/create.cpp @@ -1,8 +1,22 @@ // SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only #include "ScreenPlay/create.h" +#include "ScreenPlay/createimportvideo.h" #include "ScreenPlayUtil/util.h" -#include "qguiapplication.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ScreenPlay { @@ -19,8 +33,8 @@ namespace ScreenPlay { /*! Constructor. */ -Create::Create(const std::shared_ptr& globalVariables) - : QObject(nullptr) +Create::Create(const std::shared_ptr& globalVariables, QObject* parent) + : QObject(parent) , m_globalVariables(globalVariables) { } @@ -28,8 +42,8 @@ Create::Create(const std::shared_ptr& globalVariables) /*! Constructor for the QMLEngine. */ -Create::Create() - : QObject(nullptr) +Create::Create(QObject* parent) + : QObject(parent) { } diff --git a/ScreenPlay/src/globalvariables.cpp b/ScreenPlay/src/globalvariables.cpp index 241ec73e..685450b4 100644 --- a/ScreenPlay/src/globalvariables.cpp +++ b/ScreenPlay/src/globalvariables.cpp @@ -2,6 +2,8 @@ #include "ScreenPlay/globalvariables.h" #include "ScreenPlay/CMakeVariables.h" +#include +#include namespace ScreenPlay { diff --git a/ScreenPlay/src/installedlistfilter.cpp b/ScreenPlay/src/installedlistfilter.cpp index dce27793..48fff12d 100644 --- a/ScreenPlay/src/installedlistfilter.cpp +++ b/ScreenPlay/src/installedlistfilter.cpp @@ -1,6 +1,8 @@ // SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only #include "ScreenPlay/installedlistfilter.h" +#include "ScreenPlay/globalvariables.h" +#include namespace ScreenPlay { diff --git a/ScreenPlay/src/installedlistmodel.cpp b/ScreenPlay/src/installedlistmodel.cpp index 47426d68..f58ba422 100644 --- a/ScreenPlay/src/installedlistmodel.cpp +++ b/ScreenPlay/src/installedlistmodel.cpp @@ -2,8 +2,17 @@ #include "ScreenPlay/installedlistmodel.h" #include "ScreenPlay/CMakeVariables.h" +#include #include +#include #include +#include +#include +#include +#include +#include + +#include namespace ScreenPlay { diff --git a/ScreenPlay/src/monitorlistmodel.cpp b/ScreenPlay/src/monitorlistmodel.cpp index 044a71a5..39e6e8c2 100644 --- a/ScreenPlay/src/monitorlistmodel.cpp +++ b/ScreenPlay/src/monitorlistmodel.cpp @@ -1,10 +1,15 @@ // SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only #include "ScreenPlay/monitorlistmodel.h" +#include "ScreenPlay/screenplaywallpaper.h" + #ifdef Q_OS_WIN #include "windowsintegration.h" #endif #include + +#include + namespace ScreenPlay { /*! diff --git a/ScreenPlay/src/profilelistmodel.cpp b/ScreenPlay/src/profilelistmodel.cpp index 95252a25..58fec455 100644 --- a/ScreenPlay/src/profilelistmodel.cpp +++ b/ScreenPlay/src/profilelistmodel.cpp @@ -2,11 +2,16 @@ #include "ScreenPlay/profilelistmodel.h" +#include +#include #include +#include #include #include #include #include +#include +#include namespace ScreenPlay { diff --git a/ScreenPlay/src/projectsettingslistmodel.cpp b/ScreenPlay/src/projectsettingslistmodel.cpp index 585779ac..c2d7f69c 100644 --- a/ScreenPlay/src/projectsettingslistmodel.cpp +++ b/ScreenPlay/src/projectsettingslistmodel.cpp @@ -2,6 +2,13 @@ #include "ScreenPlay/projectsettingslistmodel.h" +#include +#include +#include +#include +#include +#include + namespace ScreenPlay { /*! diff --git a/ScreenPlay/src/screenplaymanager.cpp b/ScreenPlay/src/screenplaymanager.cpp index 71a06864..191955b7 100644 --- a/ScreenPlay/src/screenplaymanager.cpp +++ b/ScreenPlay/src/screenplaymanager.cpp @@ -3,8 +3,6 @@ #include "ScreenPlay/screenplaymanager.h" #include "ScreenPlayUtil/util.h" -#include - #include namespace ScreenPlay { @@ -26,8 +24,8 @@ ScreenPlayManager::ScreenPlayManager( : QObject { parent } { m_server = std::make_unique(); - QObject::connect(m_server.get(), &QLocalServer::newConnection, this, &ScreenPlayManager::newConnection); + QObject::connect(&m_screenPlayTimelineManager, &ScreenPlayTimelineManager::requestSaveProfiles, this, &ScreenPlayManager::requestSaveProfiles); m_server->setSocketOptions(QLocalServer::WorldAccessOption); if (!m_server->listen("ScreenPlay")) { qCritical("Could not open Local Socket with the name ScreenPlay!"); @@ -41,91 +39,30 @@ ScreenPlayManager::ScreenPlayManager( QObject::connect(this, &ScreenPlayManager::requestSaveProfiles, this, [this]() { m_saveLimiter.start(); }); - - m_contentTimer.setInterval(1000); - // Do not start the timer here. This will be done after - // we have loaded all timeline wallpaper from the config.json - QObject::connect(&m_contentTimer, &QTimer::timeout, this, &ScreenPlayManager::checkActiveWallpaperTimeline); -} - - - -/*! - \brief Checks if we need to display a different wallpaper at the current time. - - CurrentTimeline => Timeline that should currently run, based on start and endtime. - ActiveTimeline => Timeline with isActive flag set to true -*/ -void ScreenPlayManager::checkActiveWallpaperTimeline() -{ - std::shared_ptr currentTimeline = m_screenPlayTimeline.getCurrentTimeline(); - if (!currentTimeline) { - qCritical() << "No active timeline found. There must always be an active timeline."; - return; - } - - // Check for currently active timeline. - std::shared_ptr activeTimelineSection = nullptr; - for (const auto& section : m_screenPlayTimeline.m_wallpaperTimelineSectionsList) { - if (section->isActive) { - activeTimelineSection = section; - break; - } - } - - // We start the first timeline section,if there is currently no active timeline section. - // This happens at every startup. - if (!activeTimelineSection) { - activateNewTimeline(); - } - - // If timeline does not match current time, switch to new timeline. - if (activeTimelineSection) { - if (!activeTimelineSection->containsTime(QTime::currentTime()) || !activeTimelineSection->isActive) { - activateNewTimeline(); - } - } } /*! - \brief Change active timeline. We need an extra flags to know if our - timeline is active and out of time range. + \brief Inits this class instead of init in the constructor. This is because we need to check + first if another ScreenPlay instance is running. If it is not the case we call this function. */ -void ScreenPlayManager::activateNewTimeline() +void ScreenPlayManager::init( + const std::shared_ptr& globalVariables, + const std::shared_ptr& mlm, + const std::shared_ptr& settings) { - // Remove old timeline content - auto oldTimeline = m_screenPlayTimeline.findActiveWallpaperTimelineSection(); - // Will be null on startup, where there is no old timeline - if (oldTimeline) { + m_globalVariables = globalVariables; + m_monitorListModel = mlm; + m_settings = settings; - oldTimeline->isActive = false; - for (auto& activeWallpaper : oldTimeline->activeWallpaperList) { - activeWallpaper->close(); - } - // Clear all active wallpaper connections, but do not - // clear WallpaperData in case we need it again later - oldTimeline->activeWallpaperList.clear(); - } + m_screenPlayTimelineManager.setGlobalVariables(m_globalVariables); + m_screenPlayTimelineManager.setSettings(m_settings); - // Activate new timeline content - std::shared_ptr newTimelineSection = m_screenPlayTimeline.getCurrentTimeline(); - if (!newTimelineSection) { - qCritical() << "No active timeline found. There must always be an active timeline."; - return; + // Reset to default settings if we are unable to load + // the existing one + if (!loadProfiles()) { + qInfo() << "Reset default profiles.json at:" << m_globalVariables->localSettingsPath(); + m_settings->writeDefaultProfiles(); } - newTimelineSection->isActive = true; - - // Activate new wallpaper - for (const auto& wallpaper : newTimelineSection->wallpaperData) { - auto activeWallpaper = startWallpaper(wallpaper, false); - if (!activeWallpaper) { - qCritical() << "Unable to start the new wallpaper at timeline:" << newTimelineSection->identifier - << newTimelineSection->startTime << "-" << newTimelineSection->endTime; - return; - } - newTimelineSection->activeWallpaperList.push_back(activeWallpaper); - } - qInfo() << "Timeline switched successfully."; } /*! @@ -148,118 +85,22 @@ bool ScreenPlayManager::setWallpaperAtTimelineIndex( wallpaperData.file = file; wallpaperData.monitors = monitorIndex; wallpaperData.fillMode = m_settings->videoFillMode(); - bool ok = false; - for (auto& timelineSection : m_screenPlayTimeline.m_wallpaperTimelineSectionsList) { - const bool sameIndex = timelineSection->index == timelineIndex; - const bool sameIdentifier = timelineSection->identifier == identifier; - if (sameIndex && sameIdentifier) { - // TODO support more than one wallpaper per timeline - timelineSection->wallpaperData = { wallpaperData }; - ok = true; - break; - } - } - if (!ok) { - qCritical() << "Invalid sameIdentifier: " << timelineIndex << identifier; + const bool success = m_screenPlayTimelineManager.setWallpaperAtTimelineIndex(wallpaperData, timelineIndex, identifier); - printTimelines(); + if (!success) { + qCritical() << "Invalid timeline index or identifier: " << timelineIndex << identifier; + m_screenPlayTimelineManager.printTimelines(); emit printQmlTimeline(); return false; } + // We do not start the wallpaper here, but let - // ScreenPlayManager::checkActiveWallpaperTimeline decide + // ScreenPlayTimelineManager::checkActiveWallpaperTimeline decide // if the wallpaper emit requestSaveProfiles(); return true; } -/*! - \brief Inits this class instead of init in the constructor. This is because we need to check - first if another ScreenPlay instance is running. If it is not the case we call this function. -*/ -void ScreenPlayManager::init( - const std::shared_ptr& globalVariables, - const std::shared_ptr& mlm, - const std::shared_ptr& settings) -{ - m_globalVariables = globalVariables; - m_monitorListModel = mlm; - m_settings = settings; - - // Reset to default settings if we are unable to load - // the existing one - if (!loadProfiles()) { - qInfo() << "Reset default profiles.json at:" << m_globalVariables->localSettingsPath(); - m_settings->writeDefaultProfiles(); - } -} - -/*! - \brief Creates a wallpaper with a given \a monitorIndex list, \a a absoluteStoragePath folder, - a \a previewImage (relative path to the absoluteStoragePath), a default \a volume, - a \a fillMode, a \a type (htmlWallpaper, qmlWallpaper etc.), a \a saveToProfilesConfigFile bool only set to flase - if we call the method when using via the settings on startup to skip a unnecessary save. -*/ -std::shared_ptr ScreenPlayManager::startWallpaper( - WallpaperData wallpaperData, - const bool saveToProfilesConfigFile) -{ - - const int screenCount = QGuiApplication::screens().count(); - - QJsonArray monitors; - for (const int index : wallpaperData.monitors) { - monitors.append(index); - if (index > screenCount - 1) { - qWarning() << "Configuration contains invalid monitor with index: " << index << " screen count: " << screenCount; - return nullptr; - } - } - - auto saveToProfile = qScopeGuard([=, this] { - // Do not save on app start - if (saveToProfilesConfigFile) { - emit requestSaveProfiles(); - } - }); - - // Remove file:/// - wallpaperData.absolutePath = QUrl::fromUserInput(wallpaperData.absolutePath).toLocalFile(); - const QString appID = Util().generateRandomString(); - qInfo() << "Start wallpaper" << wallpaperData.absolutePath << appID; - - // Only support remove wallpaper that spans over 1 monitor - // if (wallpaperData.monitors.length() == 1) { - // int i = 0; - // for (auto& wallpaper : m_screenPlayWallpapers) { - // if (wallpaper->monitors().length() == 1) { - // if (monitors.at(0) == wallpaper->monitors().at(0)) { - // return wallpaper->replace( - // wallpaperData, - // m_settings->checkWallpaperVisible()); - // m_monitorListModel->setWallpaperMonitor(wallpaper, wallpaperData.monitors); - // } - // } - // i++; - // } - // } - - auto wallpaper = std::make_shared( - m_globalVariables, - appID, - wallpaperData, - m_settings); - - QObject::connect(wallpaper.get(), &ScreenPlayWallpaper::requestSave, this, &ScreenPlayManager::requestSaveProfiles); - QObject::connect(wallpaper.get(), &ScreenPlayWallpaper::requestClose, this, &ScreenPlayManager::removeWallpaper); - QObject::connect(wallpaper.get(), &ScreenPlayWallpaper::error, this, &ScreenPlayManager::displayErrorPopup); - if (!wallpaper->start()) { - return nullptr; - } - // m_monitorListModel->setWallpaperMonitor(wallpaper, wallpaperData.monitors); - return wallpaper; -} - /*! \brief Creates a ScreenPlayWidget object via a \a absoluteStoragePath and a \a preview image (relative path). */ @@ -311,30 +152,30 @@ bool ScreenPlayManager::startWidget( */ bool ScreenPlayManager::removeAllWallpapers(bool saveToProfile) { + // TODO + // if (m_screenPlayTimelineManager.m_wallpaperTimelineSectionsList.empty()) { + // return false; + // } - if (m_screenPlayTimeline.m_wallpaperTimelineSectionsList.empty()) { - return false; - } + // QStringList appIDs; + // auto activeTimelineSection = m_screenPlayTimelineManager.findActiveWallpaperTimelineSection(); + // if (!activeTimelineSection) { + // qWarning() << "Trying to remove all Wallpapers while findActiveSection is empty."; + // return false; + // } + // // Do not remove items from the vector you iterate on. + // for (auto& client : activeTimelineSection->activeWallpaperList) { + // appIDs.append(client->appID()); + // } - QStringList appIDs; - auto activeTimelineSection = m_screenPlayTimeline.findActiveWallpaperTimelineSection(); - if (!activeTimelineSection) { - qWarning() << "Trying to remove all Wallpapers while findActiveSection is empty."; - return false; - } - // Do not remove items from the vector you iterate on. - for (auto& client : activeTimelineSection->activeWallpaperList) { - appIDs.append(client->appID()); - } + // for (const auto& appID : appIDs) { + // if (!removeWallpaper(appID)) { + // return false; + // } + // } - for (const auto& appID : appIDs) { - if (!removeWallpaper(appID)) { - return false; - } - } - - if (saveToProfile) - emit requestSaveProfiles(); + // if (saveToProfile) + // emit requestSaveProfiles(); return true; } @@ -390,7 +231,7 @@ bool ScreenPlayManager::removeWallpaperAt(int index) */ bool ScreenPlayManager::requestProjectSettingsAtMonitorIndex(const int index) { - auto activeTimelineSection = m_screenPlayTimeline.findActiveWallpaperTimelineSection(); + auto activeTimelineSection = m_screenPlayTimelineManager.findActiveWallpaperTimelineSection(); if (!activeTimelineSection) { return false; } @@ -440,7 +281,7 @@ bool ScreenPlayManager::setWallpaperFillModeAtMonitorIndex(const int index, cons */ bool ScreenPlayManager::setAllWallpaperValue(const QString& key, const QString& value) { - auto activeTimelineSection = m_screenPlayTimeline.findActiveWallpaperTimelineSection(); + auto activeTimelineSection = m_screenPlayTimelineManager.findActiveWallpaperTimelineSection(); if (!activeTimelineSection) { return false; } @@ -458,7 +299,7 @@ bool ScreenPlayManager::setAllWallpaperValue(const QString& key, const QString& ScreenPlayWallpaper* ScreenPlayManager::getWallpaperByAppID(const QString& appID) { - auto activeTimelineSection = m_screenPlayTimeline.findActiveWallpaperTimelineSection(); + auto activeTimelineSection = m_screenPlayTimelineManager.findActiveWallpaperTimelineSection(); if (!activeTimelineSection) { return nullptr; } @@ -476,273 +317,40 @@ ScreenPlayWallpaper* ScreenPlayManager::getWallpaperByAppID(const QString& appID */ bool ScreenPlayManager::moveTimelineAt(const int index, const QString identifier, const float relativePosition, QString positionTimeString) { - m_contentTimer.stop(); - auto updateTimer = qScopeGuard([this] { m_contentTimer.start(); }); - - auto& wallpapterTimelineSection = m_screenPlayTimeline.m_wallpaperTimelineSectionsList.at(index); - QTime newPositionTime = QTime::fromString(positionTimeString, "hh:mm"); - if (!newPositionTime.isValid()) { - qWarning() << "Unable to move with invalid time:" << positionTimeString; - return false; - } - wallpapterTimelineSection->endTime = newPositionTime; - wallpapterTimelineSection->relativePosition = relativePosition; - // We set the identifier here, because we generate it in qml - // The identiefier is only used for debugging - wallpapterTimelineSection->identifier = identifier; - - const auto timelineCount = m_screenPlayTimeline.m_wallpaperTimelineSectionsList.size(); - // Only update the next timeline startTime - // if we are not end last wallpaper, that always - // must end at 24:00 - if (index <= timelineCount) { - auto& wallpapterTimelineSectionNext = m_screenPlayTimeline.m_wallpaperTimelineSectionsList.at(index + 1); - wallpapterTimelineSectionNext->startTime = newPositionTime; - } - - printTimelines(); - emit requestSaveProfiles(); - return true; + return m_screenPlayTimelineManager.moveTimelineAt(index, identifier, relativePosition, positionTimeString); } -/*! - \brief Converts a range from 0.0f - 1.0f to 00:00:00 0 23:59:59 -*/ -QString ScreenPlayManager::getTimeString(double relativeLinePosition) -{ - if (relativeLinePosition == 1.0) { - // We overwrite the endTime here - return "23:59:59"; - } - const double totalHours = relativeLinePosition * 24; - int hours = static_cast(std::floor(totalHours)); // Gets the whole hour part - double fractionalHours = totalHours - hours; - int minutes = static_cast(std::floor(fractionalHours * 60)); // Calculates the minutes - double fractionalMinutes = fractionalHours * 60 - minutes; - int seconds = static_cast(std::round(fractionalMinutes * 60)); // Calculates the seconds - - // Adjust minutes and seconds if seconds rolled over to 60 - if (seconds == 60) { - seconds = 0; - minutes += 1; - } - - // Adjust hours and minutes if minutes rolled over to 60 - if (minutes == 60) { - minutes = 0; - hours += 1; - } - - // Ensure hours wrap correctly at 24 - if (hours == 24) { - hours = 0; - } - - // Format the output to "HH:MM:SS" - return QString("%1:%2:%3").arg(hours, 2, 10, QChar('0')).arg(minutes, 2, 10, QChar('0')).arg(seconds, 2, 10, QChar('0')); -} - -/*! - \brief Update m_screenPlayTimeline.m_wallpaperTimelineSectionsList index based on the startTime; -*/ -void ScreenPlayManager::updateIndices() -{ - // Sort the vector based on startTime - std::sort(m_screenPlayTimeline.m_wallpaperTimelineSectionsList.begin(), m_screenPlayTimeline.m_wallpaperTimelineSectionsList.end(), - [](const auto& a, const auto& b) { - return a->startTime < b->startTime; - }); - - // Update the indices based on new order - for (int i = 0; i < m_screenPlayTimeline.m_wallpaperTimelineSectionsList.size(); ++i) { - m_screenPlayTimeline.m_wallpaperTimelineSectionsList[i]->index = i; - } -} - -/*! - \brief Adds a new timeline at relative position. We always shrink the timeline at the input - position and append the new one to the left. There must always (lightning) an active - timeline section. - -*/ bool ScreenPlayManager::addTimelineAt(const int index, const float reltiaveLinePosition, QString identifier) { - m_contentTimer.stop(); - auto updateTimer = qScopeGuard([this] { m_contentTimer.start(); }); - - // We always get the new endTime - const QString newStopPosition = getTimeString(reltiaveLinePosition); - QTime newStopPositionTime = QTime::fromString(newStopPosition, m_screenPlayTimeline.m_timelineTimeFormat); - if (!newStopPositionTime.isValid()) { - return false; - } - - // IMPORTANT: The new element is always on the left. The first - // handle always persists because the - // user can never delete it. It only gets "pushed" further - // to the right, by increasing the size. - - // | Insert here - // ˇ - // |-----------------------------------------------| - // 0 ID: AAA - // - // - // |-----------------------|-----------------------| - // 0 ID: BBB 1 - ID: AAA - // We directly get the new index of 0 in this example from qml - - auto newTimelineSection = std::make_shared(); - newTimelineSection->index = index; - newTimelineSection->identifier = identifier; - newTimelineSection->endTime = newStopPositionTime; - // In case we do a full reset, we must set the start time manually - if (m_screenPlayTimeline.m_wallpaperTimelineSectionsList.empty()) { - newTimelineSection->startTime = QTime::fromString("00:00:00", m_screenPlayTimeline.m_timelineTimeFormat); - } else { - - // We can use the given index here, because it points - // the the current item at that index, and we have not yet - // added our new timelineSection to our list. - newTimelineSection->startTime = m_screenPlayTimeline.m_wallpaperTimelineSectionsList.at(index)->startTime; - } - - const bool isLast = (m_screenPlayTimeline.m_wallpaperTimelineSectionsList.length() - 1) == index; - if (isLast) { - m_screenPlayTimeline.m_wallpaperTimelineSectionsList.last()->startTime = newTimelineSection->endTime; - } - - m_screenPlayTimeline.m_wallpaperTimelineSectionsList.append(newTimelineSection); - - updateIndices(); - printTimelines(); - emit requestSaveProfiles(); - return true; + const bool success = m_screenPlayTimelineManager.addTimelineAt(index, reltiaveLinePosition, identifier); + return success; } -/*! - \brief Qml function that removes all Timeline sections. Qml then creates - a new default section. -*/ -void ScreenPlayManager::removeAllTimlineSections() +QCoro::QmlTask ScreenPlayManager::removeAllTimlineSections() { - m_contentTimer.stop(); - auto updateTimer = qScopeGuard([this] { m_contentTimer.start(); }); - - // First check if there is any active wallpaper that we save in - // this shared ptr. We can have many timlines, but the current timeline - // can have no active wallpaper - - auto activeTimelineSection = m_screenPlayTimeline.findActiveWallpaperTimelineSection(); - if (!activeTimelineSection) { - qCritical() << "There must always be (lightning) an active timline"; - return; - } - - if (activeTimelineSection) { - // Close the localsocket - activeTimelineSection->close(); - // Reset all active wallpaper - activeTimelineSection.reset(); - } - - m_screenPlayTimeline.m_wallpaperTimelineSectionsList.clear(); - removeAllWallpapers(); - removeAllWidgets(); - // Do not call requestSaveProfiles, because qml will add - // the default timeline after this function + return QCoro::QmlTask([this]() -> QCoro::Task { + // call with coro + const bool success = co_await m_screenPlayTimelineManager.removeAllTimlineSections(); + qDebug() << "Task: removeAllTimlineSections" << success; + // emit requestSaveProfiles(); + // removeAllWallpapers(); + co_return Result { success }; + }()); } -/*! - \brief Removes a timeline at a given index. Expands the timeline next to it - to fill the space. -*/ bool ScreenPlayManager::removeTimelineAt(const int index) { - printTimelines(); - const auto timelineCount = m_screenPlayTimeline.m_wallpaperTimelineSectionsList.size(); - if (timelineCount == 0) { - qCritical() << "Timeline empty"; - return false; - } - if (timelineCount == 1) { - qCritical() << "Timeline must always have at least one element, that span across the whole timeline from 00:00:00 to 23:59:59."; - return false; - } - m_contentTimer.stop(); - auto updateTimer = qScopeGuard([this] { m_contentTimer.start(); }); - - auto& wallpapterTimelineSection = m_screenPlayTimeline.m_wallpaperTimelineSectionsList.at(index); - - // When we have two timelines, we know that only the first - // timeline can be removed and the second one will then span - // across the whole timeline - // remove <- expand - // |-----------|-----------| - // 0 1 - if (timelineCount == 2) { - if (index != 0) { - qCritical() << "Removing the last timeline is not allowed. This must always span the whole timeline"; - return false; - } - m_screenPlayTimeline.m_wallpaperTimelineSectionsList.removeAt(index); - m_screenPlayTimeline.m_wallpaperTimelineSectionsList.first()->startTime = QTime::fromString("00:00:00", m_screenPlayTimeline.m_timelineTimeFormat); - updateIndices(); - printTimelines(); - return true; - } - - // Now handle all states where we have more than two wallpaper - // There is no timeline before if we want to remove - // the timeline at index 0. We do not need to make the same - // check for the timelineAfter, because the last timeline - // cannot be deleted - QTime endTime; - if (index == 0) { - endTime = QTime::fromString("00:00:00", m_screenPlayTimeline.m_timelineTimeFormat); - } else { - endTime = m_screenPlayTimeline.m_wallpaperTimelineSectionsList.at(index - 1)->endTime; - } - auto timelineAfter = m_screenPlayTimeline.m_wallpaperTimelineSectionsList.at(index + 1); - // before remove <- expand - // |-----------|-----------|-----------| - // 0 1 2 - // Now when removing timeline at index 1, the next (after) - // wallpaper gets the remaining space - timelineAfter->startTime = endTime; - m_screenPlayTimeline.m_wallpaperTimelineSectionsList.removeAt(index); - updateIndices(); - printTimelines(); - + const bool success = m_screenPlayTimelineManager.removeTimelineAt(index); emit requestSaveProfiles(); - return true; + return success; } - -/*! - \brief Print to check if our qml data matches our c++. -*/ -void ScreenPlayManager::printTimelines() -{ - std::cout << "#############################\n"; - for (auto& timeline : m_screenPlayTimeline.m_wallpaperTimelineSectionsList) { - std::cout << timeline->index << ": " << timeline->identifier.toStdString() << "\t" - << timeline->relativePosition - << " start: " << timeline->startTime.toString().toStdString() - << " end: " << timeline->endTime.toString().toStdString() << std::endl; - } -} - /*! \brief Qml function to build our timeline on creation in qml. */ QJsonArray ScreenPlayManager::initialSectionsList() { - QJsonArray sectionPositions; - for (const auto& timelineSection : m_screenPlayTimeline.m_wallpaperTimelineSectionsList) { - sectionPositions.push_back(timelineSection->serialize()); - } - return sectionPositions; + return m_screenPlayTimelineManager.initialSectionsList(); } /*! @@ -775,7 +383,7 @@ void ScreenPlayManager::newConnection() return; } - auto activeTimelineSection = m_screenPlayTimeline.findActiveWallpaperTimelineSection(); + auto activeTimelineSection = m_screenPlayTimelineManager.findActiveWallpaperTimelineSection(); if (!activeTimelineSection) { return; } @@ -829,7 +437,7 @@ void ScreenPlayManager::setActiveWidgetsCounter(int activeWidgetsCounter) bool ScreenPlayManager::removeWallpaper(const QString& appID) { - auto wallpaperSectionOpt = m_screenPlayTimeline.activeWallpaperSectionByAppID(appID); + auto wallpaperSectionOpt = m_screenPlayTimelineManager.activeWallpaperSectionByAppID(appID); if (!wallpaperSectionOpt.has_value()) { qCritical() << "No wallpaper found."; return false; @@ -908,7 +516,7 @@ bool ScreenPlayManager::removeWidget(const QString& appID) */ bool ScreenPlayManager::setWallpaperValue(const QString& appID, const QString& key, const QString& value) { - std::shared_ptr activeTimelineSection = m_screenPlayTimeline.findActiveWallpaperTimelineSection(); + std::shared_ptr activeTimelineSection = m_screenPlayTimelineManager.findActiveWallpaperTimelineSection(); if (!activeTimelineSection) { qCritical() << "setWallpaperValue failed, because no active timeline section was found"; return false; @@ -931,20 +539,7 @@ bool ScreenPlayManager::saveProfiles() { m_saveLimiter.stop(); - QJsonArray timelineWallpaperList {}; - for (const auto& activeTimelineWallpaper : std::as_const(m_screenPlayTimeline.m_wallpaperTimelineSectionsList)) { - QJsonObject timelineWallpaper; - timelineWallpaper.insert("startTime", activeTimelineWallpaper->startTime.toString()); - timelineWallpaper.insert("endTime", activeTimelineWallpaper->endTime.toString()); - QJsonArray wallpaper; - // Every timeline section can have multiple wallpaper - for (const auto& wallpaperData : activeTimelineWallpaper->wallpaperData) { - wallpaper.append(wallpaperData.serialize()); - } - timelineWallpaper.insert("wallpaper", wallpaper); - - timelineWallpaperList.append(timelineWallpaper); - } + QJsonArray timelineWallpaperList = m_screenPlayTimelineManager.timelineWallpaperList(); QJsonArray widgetList {}; for (const auto& activeWidget : std::as_const(m_screenPlayWidgets)) { @@ -1007,21 +602,10 @@ bool ScreenPlayManager::loadProfiles() for (QJsonValueRef timelineWallpaper : wallpaper.toObject().value("timelineWallpaper").toArray()) { QJsonObject wallpaperObj = timelineWallpaper.toObject(); - std::optional> wallpaperDataOpt = m_screenPlayTimeline.loadTimelineWallpaperConfig(wallpaperObj); - if (!wallpaperDataOpt.has_value()) { - containsInvalidData = true; - break; + if (!m_screenPlayTimelineManager.addTimelineFromSettings(wallpaperObj)) { + qCritical() << "Unable to add wallpaper timeline"; + continue; } - - std::shared_ptr wallpaperData = wallpaperDataOpt.value(); - wallpaperData->index = m_screenPlayTimeline.m_wallpaperTimelineSectionsList.length(); - wallpaperData->identifier = m_util.generateRandomString(4); - - qInfo() << wallpaperData->index - << wallpaperData->startTime - << wallpaperData->endTime; - - m_screenPlayTimeline.m_wallpaperTimelineSectionsList.append(wallpaperDataOpt.value()); } for (const QJsonValueRef widget : wallpaper.toObject().value("widgets").toArray()) { @@ -1037,30 +621,11 @@ bool ScreenPlayManager::loadProfiles() if (containsInvalidData) saveProfiles(); - activateNewTimeline(); - m_contentTimer.start(); + m_screenPlayTimelineManager.startupFirstTimeline(); return true; } -void ScreenPlayManager::updateQmlTimelines() -{ - QVariantList data; - for (const auto& timelineSection : m_screenPlayTimeline.m_wallpaperTimelineSectionsList) { - if (timelineSection->wallpaperData.empty()) - continue; - - // We just use the frist one - const auto& wp = timelineSection->wallpaperData.front(); - data.append(QVariant::fromValue(wp.previewImage)); - } -} - - - - - - /*! \brief Loads a widget from C:\Users\XXX\AppData\Local\ScreenPlay\ScreenPlay\profiles.json */ diff --git a/ScreenPlay/src/screenplaytimeline.cpp b/ScreenPlay/src/screenplaytimeline.cpp deleted file mode 100644 index 03728c2c..00000000 --- a/ScreenPlay/src/screenplaytimeline.cpp +++ /dev/null @@ -1,106 +0,0 @@ -#include "screenplaytimeline.h" -#include "ScreenPlay/screenplaywallpaper.h" -#include "ScreenPlay/wallpaperdata.h" - -namespace ScreenPlay { -/*! - * \brief Calculates the relative position of a given time within a day. - * * This function takes a QTime object representing the end time and calculates its - * position relative to a fixed start and end time on the same day. The relative position - * is a normalized value between 0 and 1, rounded to four decimal places. - * * \param endTime The time for which to calculate the relative position. - * \return A float representing the normalized relative position of endTime, rounded to four decimal places. - */ -float ScreenPlayTimeline::calculateRelativePosition(const QTime &endTime) -{ - QTime startTime(0, 0, 0); // Start of the day - QTime maxTime(23, 59, 59); // End of the day range - - // Total number of seconds from startTime to maxTime - int totalSeconds = startTime.secsTo(maxTime); - - // Seconds from startTime to the given endTime - int endTimeSeconds = startTime.secsTo(endTime); - - // Calculate the relative position - float relativePosition = static_cast(endTimeSeconds) / totalSeconds; - - // Round to four decimal places - return qRound(relativePosition * 10000.0) / 10000.0; -} - -std::optional > ScreenPlay::ScreenPlayTimeline::loadTimelineWallpaperConfig(const QJsonObject &timelineObj) -{ - const QTime startTime = QTime::fromString(timelineObj.value("startTime").toString(), m_timelineTimeFormat); - const QTime endTime = QTime::fromString(timelineObj.value("endTime").toString(), m_timelineTimeFormat); - if (startTime > endTime) { - qCritical() << "Invalid time, start time is later than end time: " << startTime.toString() << endTime.toString(); - return std::nullopt; - } - - // TODO check license - auto timelineSection = std::make_shared(); - timelineSection->startTime = startTime; - timelineSection->endTime = endTime; - timelineSection->relativePosition = calculateRelativePosition(endTime); - const auto wallpaperList = timelineObj.value("wallpaper").toArray(); - for (auto& wallpaper : wallpaperList) { - std::optional wallpaperDataOpt = WallpaperData::loadWallpaperConfig(wallpaper.toObject()); - if (!wallpaperDataOpt.has_value()) - return std::nullopt; - timelineSection->wallpaperData.push_back(wallpaperDataOpt.value()); - } - return timelineSection; -} -/*! - \brief Parses one timeline wallpaper: - - "timelineWallpaper": [ - { - "endTime": "08:32:00", - "startTime": "00:00:00", - "wallpaper": [ - [...] - ] - }, -*/ -std::shared_ptr ScreenPlayTimeline::findActiveWallpaperTimelineSection() -{ - for (const auto& section : m_wallpaperTimelineSectionsList) { - if (section->isActive) { - return section; - } - } - return nullptr; -} -/*! - \brief Returns the wallpaper timeline that has the isActive - flag enabled. -*/ -std::optional > ScreenPlayTimeline::activeWallpaperSectionByAppID(const QString &appID) -{ - for (const auto& section : m_wallpaperTimelineSectionsList) { - for (const auto& wallpaper : section->activeWallpaperList) { - if(wallpaper->appID() == appID) - return section; - } - } - qCritical() << "No matching appID for:"<< appID; - return nullptr; -} -/*! - \brief Returns the current active timline. There must always be an active timeline! -*/ -std::shared_ptr ScreenPlayTimeline::getCurrentTimeline() -{ - const QTime currentTime = QTime::currentTime(); - for (const auto& section : m_wallpaperTimelineSectionsList) { - if (section->containsTime(currentTime)) { - return section; - } - } - qCritical() << "No active timeline"; - return nullptr; -} - -} diff --git a/ScreenPlay/src/screenplaytimelinemanager.cpp b/ScreenPlay/src/screenplaytimelinemanager.cpp new file mode 100644 index 00000000..6cb6c921 --- /dev/null +++ b/ScreenPlay/src/screenplaytimelinemanager.cpp @@ -0,0 +1,469 @@ +#include "ScreenPlay/screenplaytimelinemanager.h" +#include "ScreenPlay/screenplaywallpaper.h" +#include "ScreenPlay/wallpaperdata.h" +#include "ScreenPlayUtil/util.h" + +#include +#include +#include + +namespace ScreenPlay { + +/*! + * \brief Calculates the relative position of a given time within a day. + * * This function takes a QTime object representing the end time and calculates its + * position relative to a fixed start and end time on the same day. The relative position + * is a normalized value between 0 and 1, rounded to four decimal places. + * * \param endTime The time for which to calculate the relative position. + * \return A float representing the normalized relative position of endTime, rounded to four decimal places. + */ +ScreenPlayTimelineManager::ScreenPlayTimelineManager( + QObject* parent) + : QObject { parent } +{ + // Do not start the timer here. This will be done after + // we have loaded all timeline wallpaper from the config.json + QObject::connect(&m_contentTimer, &QTimer::timeout, this, &ScreenPlayTimelineManager::checkActiveWallpaperTimeline); + m_contentTimer.start(1000); +} + +/*! + \brief Parses one timeline wallpaper: + + "timelineWallpaper": [ + { + "endTime": "08:32:00", + "startTime": "00:00:00", + "wallpaper": [ + [...] + ] + }, +*/ +std::shared_ptr ScreenPlayTimelineManager::findActiveWallpaperTimelineSection() +{ + for (const auto& section : m_wallpaperTimelineSectionsList) { + if (section->status == WallpaperTimelineSection::Status::Active) { + return section; + } + } + return nullptr; +} +/*! + \brief Returns the wallpaper timeline that has the isActive + flag enabled. +*/ +std::optional> ScreenPlayTimelineManager::activeWallpaperSectionByAppID(const QString& appID) +{ + for (const auto& section : m_wallpaperTimelineSectionsList) { + for (const auto& wallpaper : section->activeWallpaperList) { + if(wallpaper->appID() == appID) + return section; + } + } + qCritical() << "No matching appID for:"<< appID; + return nullptr; +} + +/*! + \brief Returns the current active timline. There must always be an active timeline! +*/ +std::shared_ptr ScreenPlayTimelineManager::findTimelineForCurrentTime() +{ + const QTime currentTime = QTime::currentTime(); + for (const auto& section : m_wallpaperTimelineSectionsList) { + if (section->containsTime(currentTime)) { + return section; + } + } + qCritical() << "No active timeline"; + return nullptr; +} + +/*! + \brief Loads all timelines. +*/ +bool ScreenPlayTimelineManager::addTimelineFromSettings(const QJsonObject& timelineObj) +{ + const QTime startTime = QTime::fromString(timelineObj.value("startTime").toString(), m_timelineTimeFormat); + const QTime endTime = QTime::fromString(timelineObj.value("endTime").toString(), m_timelineTimeFormat); + if (startTime > endTime) { + qCritical() << "Invalid time, start time is later than end time: " << startTime.toString() << endTime.toString(); + return false; + } + + // TODO check license + auto timelineSection = std::make_shared(); + QObject::connect(timelineSection.get(), &WallpaperTimelineSection::requestSaveProfiles, this, &ScreenPlayTimelineManager::requestSaveProfiles); + timelineSection->startTime = startTime; + timelineSection->endTime = endTime; + timelineSection->settings = m_settings; + timelineSection->globalVariables = m_globalVariables; + timelineSection->relativePosition = Util().calculateRelativePosition(endTime); + const auto wallpaperList = timelineObj.value("wallpaper").toArray(); + for (auto& wallpaper : wallpaperList) { + std::optional wallpaperDataOpt = WallpaperData::loadWallpaperConfig(wallpaper.toObject()); + if (!wallpaperDataOpt.has_value()) + return false; + timelineSection->wallpaperDataList.push_back(wallpaperDataOpt.value()); + } + + // Todo: Should we use addTimelineAt? + timelineSection->index = m_wallpaperTimelineSectionsList.length(); + timelineSection->identifier = Util().generateRandomString(4); + + qInfo() << timelineSection->index + << timelineSection->startTime + << timelineSection->endTime; + + // Todo: Should we use addTimelineAt? + m_wallpaperTimelineSectionsList.append(timelineSection); + return false; +} + +/*! + \brief We always handle the endTimeString, because it is the handle for the + timeline. The last, default, timeline does not have a handle. +*/ +bool ScreenPlayTimelineManager::moveTimelineAt(const int index, const QString identifier, const float relativePosition, QString positionTimeString) +{ + m_contentTimer.stop(); + auto updateTimer = qScopeGuard([this] { m_contentTimer.start(); }); + + auto& wallpapterTimelineSection = m_wallpaperTimelineSectionsList.at(index); + QTime newPositionTime = QTime::fromString(positionTimeString, "hh:mm"); + if (!newPositionTime.isValid()) { + qWarning() << "Unable to move with invalid time:" << positionTimeString; + return false; + } + wallpapterTimelineSection->endTime = newPositionTime; + wallpapterTimelineSection->relativePosition = relativePosition; + // We set the identifier here, because we generate it in qml + // The identiefier is only used for debugging + wallpapterTimelineSection->identifier = identifier; + + const auto timelineCount = m_wallpaperTimelineSectionsList.size(); + // Only update the next timeline startTime + // if we are not end last wallpaper, that always + // must end at 24:00 + if (index <= timelineCount) { + auto& wallpapterTimelineSectionNext = m_wallpaperTimelineSectionsList.at(index + 1); + wallpapterTimelineSectionNext->startTime = newPositionTime; + } + + // printTimelines(); + emit requestSaveProfiles(); + return true; +} + +/*! + \brief Checks if we need to display a different wallpaper at the current time. +*/ +void ScreenPlayTimelineManager::checkActiveWallpaperTimeline() +{ + // Current timeline with the state active + std::shared_ptr activeTimeline = findActiveWallpaperTimelineSection(); + + if (!activeTimeline) { + std::shared_ptr currentTimeline = findTimelineForCurrentTime(); + currentTimeline->activateTimeline(); + return; + } + // Current timline that should be active, based on the current time + std::shared_ptr currentTimeline = findTimelineForCurrentTime(); + if (!currentTimeline) { + qCritical() << "No current timeline found. There must always be an active timeline."; + return; + } + + if (currentTimeline != activeTimeline) { + activeTimeline->deactivateTimeline(); + currentTimeline->activateTimeline(); + } +} + +void ScreenPlayTimelineManager::setSettings(const std::shared_ptr& settings) +{ + m_settings = settings; +} + +void ScreenPlayTimelineManager::startupFirstTimeline() +{ + std::shared_ptr currentTimeline = findTimelineForCurrentTime(); + if (!currentTimeline) { + qCritical() << "No current timeline found. There must always be an active timeline."; + return; + } + currentTimeline->activateTimeline(); +} + +void ScreenPlayTimelineManager::setGlobalVariables(const std::shared_ptr& globalVariables) +{ + m_globalVariables = globalVariables; +} + +bool ScreenPlayTimelineManager::deactivateCurrentTimeline() +{ + auto oldTimeline = findActiveWallpaperTimelineSection(); + if (!oldTimeline) { + qCritical() << "No active timeline found. There must always be an active timeline."; + return false; + } + oldTimeline->deactivateTimeline(); + return true; +} +/*! + \brief Change active timeline. We need an extra flags to know if our + timeline is active and out of time range. +*/ +bool ScreenPlayTimelineManager::startTimeline() +{ + + std::shared_ptr newTimelineSection = findTimelineForCurrentTime(); + if (!newTimelineSection) { + qCritical() << "No new timeline found. There must always be an active timeline."; + return false; + } + if (!newTimelineSection->activateTimeline()) { + qCritical() << "Unable activate timeline."; + return false; + } + + qInfo() << "Timeline switched successfully."; + return true; +} + +/*! + \brief Update m_wallpaperTimelineSectionsList index based on the startTime; +*/ +void ScreenPlayTimelineManager::updateIndices() +{ + // Sort the vector based on startTime + std::sort(m_wallpaperTimelineSectionsList.begin(), m_wallpaperTimelineSectionsList.end(), + [](const auto& a, const auto& b) { + return a->startTime < b->startTime; + }); + + // Update the indices based on new order + for (int i = 0; i < m_wallpaperTimelineSectionsList.size(); ++i) { + m_wallpaperTimelineSectionsList[i]->index = i; + } +} + +/*! + \brief Adds a new timeline at relative position. We always shrink the timeline at the input + position and append the new one to the left. There must always (lightning) an active + timeline section. + + */ +bool ScreenPlayTimelineManager::addTimelineAt(const int index, const float reltiaveLinePosition, QString identifier) +{ + // We always get the new endTime + const QString newStopPosition = Util().getTimeString(reltiaveLinePosition); + QTime newStopPositionTime = QTime::fromString(newStopPosition, m_timelineTimeFormat); + if (!newStopPositionTime.isValid()) { + return false; + } + + // IMPORTANT: The new element is always on the left. The first + // handle always persists because the + // user can never delete it. It only gets "pushed" further + // to the right, by increasing the size. + + // | Insert here + // ˇ + // |-----------------------------------------------| + // 0 ID: AAA + // + // + // |-----------------------|-----------------------| + // 0 ID: BBB 1 - ID: AAA + // We directly get the new index of 0 in this example from qml + + auto newTimelineSection = std::make_shared(); + QObject::connect(newTimelineSection.get(), &WallpaperTimelineSection::requestSaveProfiles, this, &ScreenPlayTimelineManager::requestSaveProfiles); + newTimelineSection->settings = m_settings; + newTimelineSection->globalVariables = m_globalVariables; + newTimelineSection->index = index; + newTimelineSection->identifier = identifier; + newTimelineSection->endTime = newStopPositionTime; + // In case we do a full reset, we must set the start time manually + if (m_wallpaperTimelineSectionsList.empty()) { + newTimelineSection->startTime = QTime::fromString("00:00:00", m_timelineTimeFormat); + } else { + + // We can use the given index here, because it points + // the the current item at that index, and we have not yet + // added our new timelineSection to our list. + newTimelineSection->startTime = m_wallpaperTimelineSectionsList.at(index)->startTime; + } + + const bool isLast = (m_wallpaperTimelineSectionsList.length() - 1) == index; + if (isLast) { + m_wallpaperTimelineSectionsList.last()->startTime = newTimelineSection->endTime; + } + + m_wallpaperTimelineSectionsList.append(newTimelineSection); + + updateIndices(); + printTimelines(); + emit requestSaveProfiles(); + return true; +} + +/*! + \brief Qml function that removes all Timeline sections. Qml then creates + a new default section. +*/ +QCoro::Task ScreenPlayTimelineManager::removeAllTimlineSections() +{ + + // First check if there is any active wallpaper and disable it + auto activeTimelineSection = findActiveWallpaperTimelineSection(); + if (activeTimelineSection) { + // First deactivate so the wallpaper has time to shutdown + co_await activeTimelineSection->deactivateTimeline(); + } + + // After we have disconnected or timed out we remove the wallpaper + m_wallpaperTimelineSectionsList.clear(); + + // Do not call requestSaveProfiles, because qml will add + // the default timeline after this function + co_return true; +} + +/*! + \brief Removes a timeline at a given index. Expands the timeline next to it + to fill the space. +*/ +bool ScreenPlayTimelineManager::removeTimelineAt(const int index) +{ + printTimelines(); + const auto timelineCount = m_wallpaperTimelineSectionsList.size(); + if (timelineCount == 0) { + qCritical() << "Timeline empty"; + return false; + } + if (timelineCount == 1) { + qCritical() << "Timeline must always have at least one element, that span across the whole timeline from 00:00:00 to 23:59:59."; + return false; + } + + auto& wallpapterTimelineSection = m_wallpaperTimelineSectionsList.at(index); + + // When we have two timelines, we know that only the first + // timeline can be removed and the second one will then span + // across the whole timeline + // remove <- expand + // |-----------|-----------| + // 0 1 + if (timelineCount == 2) { + if (index != 0) { + qCritical() << "Removing the last timeline is not allowed. This must always span the whole timeline"; + return false; + } + m_wallpaperTimelineSectionsList.removeAt(index); + m_wallpaperTimelineSectionsList.first()->startTime = QTime::fromString("00:00:00", m_timelineTimeFormat); + updateIndices(); + printTimelines(); + return true; + } + + // Now handle all states where we have more than two wallpaper + // There is no timeline before if we want to remove + // the timeline at index 0. We do not need to make the same + // check for the timelineAfter, because the last timeline + // cannot be deleted + QTime endTime; + if (index == 0) { + endTime = QTime::fromString("00:00:00", m_timelineTimeFormat); + } else { + endTime = m_wallpaperTimelineSectionsList.at(index - 1)->endTime; + } + auto timelineAfter = m_wallpaperTimelineSectionsList.at(index + 1); + // before remove <- expand + // |-----------|-----------|-----------| + // 0 1 2 + // Now when removing timeline at index 1, the next (after) + // wallpaper gets the remaining space + timelineAfter->startTime = endTime; + m_wallpaperTimelineSectionsList.removeAt(index); + updateIndices(); + printTimelines(); + + return true; +} + +void ScreenPlayTimelineManager::printTimelines() +{ + std::cout << "#############################\n"; + for (auto& timeline : m_wallpaperTimelineSectionsList) { + std::cout << timeline->index << ": " << timeline->identifier.toStdString() << "\t" + << timeline->relativePosition + << " start: " << timeline->startTime.toString().toStdString() + << " end: " << timeline->endTime.toString().toStdString() << std::endl; + } +} + +bool ScreenPlayTimelineManager::setWallpaperAtTimelineIndex(WallpaperData wallpaperData, const int timelineIndex, const QString& identifier) +{ + bool found = false; + for (auto& timelineSection : m_wallpaperTimelineSectionsList) { + const bool sameIndex = timelineSection->index == timelineIndex; + const bool sameIdentifier = timelineSection->identifier == identifier; + if (sameIndex && sameIdentifier) { + found = true; + + // Check if we already have a wallpaper at the same position or on one or more of the specified monitors + auto it = std::find_if(timelineSection->wallpaperDataList.begin(), timelineSection->wallpaperDataList.end(), + [&wallpaperData](const WallpaperData& existingWallpaper) { + return std::any_of(wallpaperData.monitors.begin(), wallpaperData.monitors.end(), + [&existingWallpaper](int monitor) { + return existingWallpaper.monitors.contains(monitor); + }); + }); + + if (it != timelineSection->wallpaperDataList.end()) { + // Overwrite the existing wallpaper + *it = wallpaperData; + } else { + // Append the new wallpaper data + timelineSection->wallpaperDataList.push_back(wallpaperData); + // Start all wallpaper + timelineSection->activateTimeline(); + } + + break; + } + } + return found; +} + +QJsonArray ScreenPlayTimelineManager::initialSectionsList() +{ + QJsonArray sectionPositions; + for (const auto& timelineSection : m_wallpaperTimelineSectionsList) { + sectionPositions.push_back(timelineSection->serialize()); + } + return sectionPositions; +} + +QJsonArray ScreenPlayTimelineManager::timelineWallpaperList() +{ + QJsonArray timelineWallpaperList {}; + for (const auto& activeTimelineWallpaper : std::as_const(m_wallpaperTimelineSectionsList)) { + QJsonObject timelineWallpaper; + timelineWallpaper.insert("startTime", activeTimelineWallpaper->startTime.toString()); + timelineWallpaper.insert("endTime", activeTimelineWallpaper->endTime.toString()); + QJsonArray wallpaper; + // Every timeline section can have multiple wallpaper + for (const auto& wallpaperData : activeTimelineWallpaper->wallpaperDataList) { + wallpaper.append(wallpaperData.serialize()); + } + timelineWallpaper.insert("wallpaper", wallpaper); + + timelineWallpaperList.append(timelineWallpaper); + } + return timelineWallpaperList; +} +} diff --git a/ScreenPlay/src/screenplaywallpaper.cpp b/ScreenPlay/src/screenplaywallpaper.cpp index 7155c239..5c27b7fe 100644 --- a/ScreenPlay/src/screenplaywallpaper.cpp +++ b/ScreenPlay/src/screenplaywallpaper.cpp @@ -1,7 +1,10 @@ // SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only #include "ScreenPlay/screenplaywallpaper.h" +#include "ScreenPlayUtil/util.h" -#include "util.h" +#include +#include +#include namespace ScreenPlay { @@ -259,7 +262,7 @@ void ScreenPlayWallpaper::setSDKConnection(std::unique_ptr connec std::optional running = m_processManager.isRunning(m_processID); if (running.has_value()) { - // qInfo() << "running:" << running.value(); + qInfo() << "running:" << running.value(); } else { qInfo() << "INVALID PID:" << m_processID; } diff --git a/ScreenPlay/src/screenplaywidget.cpp b/ScreenPlay/src/screenplaywidget.cpp index f2b98180..19785af2 100644 --- a/ScreenPlay/src/screenplaywidget.cpp +++ b/ScreenPlay/src/screenplaywidget.cpp @@ -1,5 +1,9 @@ // SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only #include "ScreenPlay/screenplaywidget.h" +#include "ScreenPlayUtil/util.h" + +#include +#include namespace ScreenPlay { @@ -115,7 +119,7 @@ void ScreenPlayWidget::setSDKConnection(std::unique_ptr connectio std::optional running = m_processManager.isRunning(m_processID); if (running.has_value()) { - qInfo() << "running:" << running.value(); + // qInfo() << "running:" << running.value(); } else { qInfo() << "INVALID PID:" << m_processID; } diff --git a/ScreenPlay/src/sdkconnection.cpp b/ScreenPlay/src/sdkconnection.cpp index 4402f7d1..f688c2d9 100644 --- a/ScreenPlay/src/sdkconnection.cpp +++ b/ScreenPlay/src/sdkconnection.cpp @@ -1,5 +1,13 @@ // SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only #include "ScreenPlay/sdkconnection.h" +#include "ScreenPlay/globalvariables.h" +#include "ScreenPlayUtil/util.h" + +#include +#include +#include +#include +#include namespace ScreenPlay { @@ -90,7 +98,7 @@ void ScreenPlay::SDKConnection::readyRead() emit jsonMessageReceived(doc.object()); } else { - qInfo() << "### Message from: " << m_appID << ": " << msg; + // qInfo() << "### Message from: " << m_appID << ": " << msg; } } } diff --git a/ScreenPlay/src/settings.cpp b/ScreenPlay/src/settings.cpp index 346f9b1a..9214de62 100644 --- a/ScreenPlay/src/settings.cpp +++ b/ScreenPlay/src/settings.cpp @@ -1,10 +1,33 @@ // SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only #include "ScreenPlay/settings.h" -#include "ScreenPlayUtil/util.h" -#include -#include - #include "ScreenPlay/CMakeVariables.h" +#include "ScreenPlayUtil/util.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #ifdef Q_OS_WIN #include diff --git a/ScreenPlay/src/wallpapertimelinesection.cpp b/ScreenPlay/src/wallpapertimelinesection.cpp index 96a6f533..983bbf68 100644 --- a/ScreenPlay/src/wallpapertimelinesection.cpp +++ b/ScreenPlay/src/wallpapertimelinesection.cpp @@ -1,10 +1,147 @@ -#include "wallpapertimelinesection.h" +#include "ScreenPlay/wallpapertimelinesection.h" #include "ScreenPlay/screenplaywallpaper.h" +#include "ScreenPlay/wallpaperdata.h" +#include "ScreenPlayUtil/util.h" +#include +#include +#include +#include +#include -bool ScreenPlay::WallpaperTimelineSection::close(){ - for (auto& wallpaper : activeWallpaperList) { - wallpaper->close(); +namespace ScreenPlay { + +bool WallpaperTimelineSection::containsTime(const QTime& time) const +{ + if (endTime < startTime) { // Timeline spans midnight + return (time >= startTime || time < endTime); + } else { + return (time >= startTime && time < endTime); + } +} + +QJsonObject WallpaperTimelineSection::serialize() const +{ + QJsonObject data; + data.insert("identifier", identifier); + data.insert("index", index); + data.insert("relativePosition", relativePosition); + data.insert("startTime", startTime.toString()); + data.insert("endTime", endTime.toString()); + + // Serialize vector + QJsonArray wallpaperDataArray; + for (const auto& wallpaper : wallpaperDataList) { + QJsonObject wallpaperObject = wallpaper.serialize(); // Assuming WallpaperData has a serialize method + wallpaperDataArray.append(wallpaperObject); + } + data.insert("wallpaperData", wallpaperDataArray); + + // Serialize vector> + // QJsonArray activeWallpaperArray; + // for (const auto& wallpaper : activeWallpaperList) { + // QJsonObject wallpaperObject = wallpaper->serialize(); // Assuming ScreenPlayWallpaper has a serialize method + // activeWallpaperArray.append(wallpaperObject); + // } + // data.insert("activeWallpaperList", activeWallpaperArray); + + return data; +} + +// Start all ScreenPlayWallpaper processes of this current timeline +bool WallpaperTimelineSection::activateTimeline() +{ + status = Status::Active; + // TODO: this can be called if the timeline is already active. + // Add a check to only launch new + for (auto& wallpaperData : wallpaperDataList) { + + const int screenCount = QGuiApplication::screens().count(); + + QJsonArray monitors; + for (const int index : wallpaperData.monitors) { + monitors.append(index); + if (index > screenCount - 1) { + qWarning() << "Configuration contains invalid monitor with index: " << index << " screen count: " << screenCount; + return false; + } + } + + // Remove file:/// + wallpaperData.absolutePath = QUrl::fromUserInput(wallpaperData.absolutePath).toLocalFile(); + const QString appID = Util().generateRandomString(); + qInfo() << "Start wallpaper" << wallpaperData.absolutePath << appID; + + // Only support remove wallpaper that spans over 1 monitor + // if (wallpaper.monitors.length() == 1) { + // int i = 0; + // for (auto& wallpaper : m_screenPlayWallpapers) { + // if (wallpaper->monitors().length() == 1) { + // if (monitors.at(0) == wallpaper->monitors().at(0)) { + // return wallpaper->replace( + // wallpaper, + // settings->checkWallpaperVisible()); + // m_monitorListModel->setWallpaperMonitor(wallpaper, wallpaper.monitors); + // } + // } + // i++; + // } + // } + + auto screenPlayWallpaper = std::make_shared( + globalVariables, + appID, + wallpaperData, + settings); + + QObject::connect(screenPlayWallpaper.get(), &ScreenPlayWallpaper::requestSave, this, [this]() { + // &ScreenPlayManager::requestSaveProfiles + emit requestSaveProfiles(); + }); + QObject::connect(screenPlayWallpaper.get(), &ScreenPlayWallpaper::requestClose, this, []() { + // , &ScreenPlayManager::removeWallpaper); + }); + + // QObject::connect(screenPlayWallpaper.get(), &ScreenPlayWallpaper::error, this, this, []() { + // // , &ScreenPlayManager::displayErrorPopup); + // }); + if (!screenPlayWallpaper->start()) { + return false; + } + // m_monitorListModel->setWallpaperMonitor(wallpaper, wallpaperData.monitors); + activeWallpaperList.push_back(screenPlayWallpaper); } - activeWallpaperList.clear(); return true; } + +QCoro::Task WallpaperTimelineSection::deactivateTimeline() +{ + + status = Status::Closing; + for (auto& activeWallpaper : activeWallpaperList) { + activeWallpaper->close(); + } + QTimer timer; + timer.start(250); + const int maxRetries = 30; + for (int i = 1; i <= maxRetries; ++i) { + // Wait for the timer to tick + co_await timer; + bool wallpaperStillActive = false; + for (auto& activeWallpaper : activeWallpaperList) { + if (activeWallpaper->isConnected()) { + wallpaperStillActive = true; + break; + } + } + if (!wallpaperStillActive) { + status = Status::Inactive; + // Clear all active wallpaper connections, but do not + // clear WallpaperData in case we need it again later + activeWallpaperList.clear(); + co_return true; + } + } + co_return false; +} + +} diff --git a/ScreenPlay/src/wizards.cpp b/ScreenPlay/src/wizards.cpp index 5f7601aa..b79b556f 100644 --- a/ScreenPlay/src/wizards.cpp +++ b/ScreenPlay/src/wizards.cpp @@ -1,5 +1,23 @@ // SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only #include "ScreenPlay/wizards.h" +#include "ScreenPlay/CMakeVariables.h" +#include "ScreenPlayUtil/util.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include namespace ScreenPlay { /*! diff --git a/ScreenPlayUtil/inc/public/ScreenPlayUtil/util.h b/ScreenPlayUtil/inc/public/ScreenPlayUtil/util.h index 6b33b52f..9f4f4e28 100644 --- a/ScreenPlayUtil/inc/public/ScreenPlayUtil/util.h +++ b/ScreenPlayUtil/inc/public/ScreenPlayUtil/util.h @@ -134,6 +134,7 @@ public: Q_INVOKABLE void requestAllLicenses(); Q_INVOKABLE void requestDataProtection(); Q_INVOKABLE bool fileExists(const QString& filePath) const; + Q_INVOKABLE float calculateRelativePosition(const QTime& endTime) const; Q_INVOKABLE void setNavigation(QString nav) { @@ -151,6 +152,11 @@ public: emit requestToggleWallpaperConfiguration(); } + /*! + \brief Converts a range from 0.0f - 1.0f to 00:00:00 0 23:59:59 + */ + Q_INVOKABLE QString getTimeString(double relativeLinePosition); + signals: void extractionProgressChanged(QString file, int proc, int total, qint64 br, qint64 bt); void extractionFinished(); diff --git a/ScreenPlayUtil/src/util.cpp b/ScreenPlayUtil/src/util.cpp index 161e6612..dc5bc672 100644 --- a/ScreenPlayUtil/src/util.cpp +++ b/ScreenPlayUtil/src/util.cpp @@ -608,6 +608,58 @@ bool Util::fileExists(const QString& filePath) const return file.isFile(); } +float Util::calculateRelativePosition(const QTime& endTime) const +{ + QTime startTime(0, 0, 0); // Start of the day + QTime maxTime(23, 59, 59); // End of the day range + + // Total number of seconds from startTime to maxTime + int totalSeconds = startTime.secsTo(maxTime); + + // Seconds from startTime to the given endTime + int endTimeSeconds = startTime.secsTo(endTime); + + // Calculate the relative position + float relativePosition = static_cast(endTimeSeconds) / totalSeconds; + + // Round to four decimal places + return qRound(relativePosition * 10000.0) / 10000.0; +} + +QString Util::getTimeString(double relativeLinePosition) +{ + if (relativeLinePosition == 1.0) { + // We overwrite the endTime here + return "23:59:59"; + } + const double totalHours = relativeLinePosition * 24; + int hours = static_cast(std::floor(totalHours)); // Gets the whole hour part + double fractionalHours = totalHours - hours; + int minutes = static_cast(std::floor(fractionalHours * 60)); // Calculates the minutes + double fractionalMinutes = fractionalHours * 60 - minutes; + int seconds = static_cast(std::round(fractionalMinutes * 60)); // Calculates the seconds + + // Adjust minutes and seconds if seconds rolled over to 60 + if (seconds == 60) { + seconds = 0; + minutes += 1; + } + + // Adjust hours and minutes if minutes rolled over to 60 + if (minutes == 60) { + minutes = 0; + hours += 1; + } + + // Ensure hours wrap correctly at 24 + if (hours == 24) { + hours = 0; + } + + // Format the output to "HH:MM:SS" + return QString("%1:%2:%3").arg(hours, 2, 10, QChar('0')).arg(minutes, 2, 10, QChar('0')).arg(seconds, 2, 10, QChar('0')); +} + /*! \brief Takes reference to \a obj. If the copy of the thumbnail is successful, it adds the corresponding settings entry to the json object reference. diff --git a/Tools/pre-commit/ollama_code_review.py b/Tools/pre-commit/ollama_code_review.py new file mode 100644 index 00000000..392205da --- /dev/null +++ b/Tools/pre-commit/ollama_code_review.py @@ -0,0 +1,124 @@ +# File: Tools/pre-commit/ollama_code_review.py + +import sys +import asyncio +import subprocess +import re +from typing import Optional, Sequence, List, Tuple +from ollama import AsyncClient + +MODEL_NAME = 'glm4' # You can change this to any model you prefer +ANALYSIS_TIMEOUT = 60 # Timeout in seconds for each file analysis + +def get_git_staged_diff() -> str: + """Get the git diff of staged changes.""" + try: + result = subprocess.run(['git', 'diff', '--cached'], capture_output=True, text=True, check=True) + return result.stdout + except subprocess.CalledProcessError as e: + print(f"Error getting git diff: {e}") + sys.exit(1) + +def parse_git_diff(diff: str) -> List[Tuple[str, str]]: + """Parse git diff and return a list of (filename, file_diff) tuples.""" + file_diffs = [] + current_file = None + current_diff = [] + + for line in diff.split('\n'): + if line.startswith('diff --git'): + if current_file: + file_diffs.append((current_file, '\n'.join(current_diff))) + current_file = re.search(r'b/(.+)$', line).group(1) + current_diff = [line] + elif current_file: + current_diff.append(line) + + if current_file: + file_diffs.append((current_file, '\n'.join(current_diff))) + + return file_diffs + + +async def analyze_file_with_ollama(filename: str, file_diff: str) -> None: + """Send a single file diff to Ollama for analysis and stream the response.""" + prompt = f""" + Analyze the following git diff for the file '{filename}'. + + Focus only on: + 1. Copy-paste errors: Look for actual repeated code blocks or patterns that suggest copy-pasting, ignoring the '+' and '-' at the start of lines. + 2. Spelling issues: Identify any misspelled words or typos in comments and strings. Ignore variable names, function names, and other code identifiers. + + Use the following emoji system to indicate the severity of issues: + 🟢 - No issues found + 🟡 - Minor issues (e.g., a few typos or small repeated code segments) + 🔴 - Significant issues (e.g., large blocks of copied code or numerous spelling errors) + + Start your response with one of these emojis to indicate the overall status. + Then provide a concise summary of findings, if any. If no issues are found, just state that. + + Git diff for {filename}: + {file_diff} + """ + + try: + client = AsyncClient() + print(f"\nAnalyzing {file_diff}:") + + full_response = [] + async def process_stream(): + async for response in await client.generate(model=MODEL_NAME, prompt=prompt, stream=True): + chunk = response['response'] + full_response.append(chunk) + print(chunk, end='', flush=True) + + await asyncio.wait_for(process_stream(), timeout=ANALYSIS_TIMEOUT) + print() # New line after complete response + except asyncio.TimeoutError: + print(f"\nAnalysis for {filename} timed out after {ANALYSIS_TIMEOUT} seconds.") + except Exception as e: + print(f"\nError communicating with Ollama for {filename}: {e}") + +async def check_and_pull_model() -> bool: + """Check if the model exists, and pull it if it doesn't.""" + client = AsyncClient() + try: + # Check if the model exists + models = await client.list() + if MODEL_NAME not in [model['name'] for model in models['models']]: + print(f"Model '{MODEL_NAME}' not found. Pulling it now...") + await client.pull(model=MODEL_NAME) + print(f"Model '{MODEL_NAME}' has been pulled successfully.") + return True + except Exception as e: + print(f"Error checking or pulling the model: {e}") + return False + +async def main(argv: Optional[Sequence[str]] = None) -> int: + # First, check and pull the model if necessary + if not await check_and_pull_model(): + print("Failed to ensure the model is available. Exiting.") + return 1 + + full_diff = get_git_staged_diff() + if not full_diff: + print("No staged changes to analyze.") + return 0 + + file_diffs = parse_git_diff(full_diff) + + for filename, file_diff in file_diffs: + await analyze_file_with_ollama(filename, file_diff) + + # Ask user if they want to proceed with the commit + while True: + answer = input("\nDo you want to proceed with the commit? (y/n): ").lower() + if answer in ['y', 'yes']: + return 0 # Proceed with commit + elif answer in ['n', 'no']: + return 1 # Abort commit + else: + print("Please answer 'y' or 'n'.") + +if __name__ == "__main__": + sys.exit(asyncio.run(main())) \ No newline at end of file