1
0
mirror of https://gitlab.com/kelteseth/ScreenPlay.git synced 2024-11-21 18:22:29 +01:00

Refactor timelines

Fix monitorlistmodel and add mock
monitor list for easier testing

Add working active wallpaper preview based on
selected timeline

Change many calls to use coroutines that make the
async handling of wallpaper closing 1000x easier

Fix wallpaper count based on actual connected wallpaper
and not based on started

Add LineIndicator user selected indicator
This commit is contained in:
Elias Steurer 2024-07-25 18:16:17 +02:00
parent ee47a6d968
commit 0ad84736c0
24 changed files with 765 additions and 529 deletions

View File

@ -31,8 +31,8 @@ Rectangle {
text: "Exit"
onClicked: {
Qt.callLater(function () {
Wallpaper.terminate();
});
Wallpaper.terminate();
});
}
}
}

View File

@ -27,14 +27,14 @@ Item {
Component.onCompleted: {
request("http://xkcd.com/info.0.json", function (o) {
if (o.status === 200) {
var d = eval('new Object(' + o.responseText + ')');
console.log(o.responseText);
img.source = d.img;
} else {
console.log("Some error has occurred");
}
});
if (o.status === 200) {
var d = eval('new Object(' + o.responseText + ')');
console.log(o.responseText);
img.source = d.img;
} else {
console.log("Some error has occurred");
}
});
}
Image {

View File

@ -1,8 +1,6 @@
// SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only
#pragma once
#include <QString>
#include "ScreenPlay/create.h"
#include "ScreenPlay/globalvariables.h"
#include "ScreenPlay/installedlistfilter.h"
@ -13,8 +11,9 @@
#include "ScreenPlay/settings.h"
#include "ScreenPlay/wizards.h"
#include "ScreenPlayUtil/util.h"
#include <QQmlEngine>
#include <QQmlEngine>
#include <QString>
#include <memory>
#if defined(Q_OS_WIN)

View File

@ -13,6 +13,7 @@
#include <optional>
#include "ScreenPlay/wallpapertimelinesection.h"
#include "ScreenPlayUtil/contenttypes.h"
namespace ScreenPlay {
@ -28,6 +29,9 @@ struct Monitor {
int m_index { 0 };
QRect m_geometry;
QString m_wallpaperPreviewImage;
QString m_appID;
ContentTypes::InstalledType m_installedType = ContentTypes::InstalledType::Unknown;
};
class MonitorListModel : public QAbstractListModel {
@ -50,15 +54,15 @@ public:
QHash<int, QByteArray> roleNames() const override;
int rowCount(const QModelIndex& parent = QModelIndex()) const override;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
void setWallpaperMonitor(const std::shared_ptr<WallpaperTimelineSection>& timelineSection,
const QVector<int> monitors);
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
std::optional<QString> getAppIDByMonitorIndex(const int index) const;
Q_INVOKABLE void reset();
Q_INVOKABLE QRect absoluteDesktopSize() const;
Q_INVOKABLE QRect absoluteDesktopSize() const;
Q_INVOKABLE QSize totalDesktopSize() const;
bool setData(const QModelIndex& index, const QVariant& value, int role) override;
signals:
void monitorReloadCompleted();
void setNewActiveMonitor(int index, QString path);
@ -82,7 +86,7 @@ private:
private:
QVector<Monitor> m_monitorList;
std::shared_ptr<WallpaperTimelineSection> m_activeTimelineSection;
bool m_useMockMonitors = false;
QVector<QVector<Monitor>> m_mockMonitorList;
};
}

View File

@ -19,7 +19,6 @@
namespace ScreenPlay {
class ScreenPlayManager : public QObject {
Q_OBJECT
QML_ELEMENT
@ -36,13 +35,9 @@ public:
const std::shared_ptr<MonitorListModel>& mlm,
const std::shared_ptr<Settings>& settings);
std::shared_ptr<ScreenPlayWallpaper> startWallpaper(
WallpaperData wallpaperData,
const bool saveToProfilesConfigFile);
Q_INVOKABLE bool removeAllWallpapers(bool saveToProfile = false);
Q_INVOKABLE QCoro::QmlTask removeAllWallpapers(bool saveToProfile = false);
Q_INVOKABLE bool removeAllWidgets(bool saveToProfile = false);
Q_INVOKABLE bool removeWallpaperAt(const int index);
Q_INVOKABLE QCoro::QmlTask removeWallpaperAt(const int timelineIndex, const QString timelineIdentifier, const int monitorIndex);
Q_INVOKABLE ScreenPlayWallpaper* getWallpaperByAppID(const QString& appID);
@ -58,7 +53,7 @@ public:
Q_INVOKABLE QCoro::QmlTask removeAllTimlineSections();
Q_INVOKABLE bool removeTimelineAt(const int index);
Q_INVOKABLE QJsonArray initialSectionsList();
Q_INVOKABLE bool setWallpaperAtTimelineIndex(
Q_INVOKABLE QCoro::QmlTask setWallpaperAtTimelineIndex(
const ScreenPlay::ContentTypes::InstalledType type,
const QString& absolutePath,
const QString& previewImage,
@ -77,12 +72,14 @@ public:
const QJsonObject& properties,
const bool saveToProfilesConfigFile);
Q_INVOKABLE void setSelectedTimelineIndex(const int selectedTimelineIndex);
Q_INVOKABLE bool requestProjectSettingsAtMonitorIndex(const int index);
Q_INVOKABLE bool setWallpaperValueAtMonitorIndex(const int index, const QString& key, const QString& value);
Q_INVOKABLE bool setWallpaperFillModeAtMonitorIndex(const int index, const int fillmode);
Q_INVOKABLE bool setAllWallpaperValue(const QString& key, const QString& value);
Q_INVOKABLE bool setWallpaperValue(const QString& appID, const QString& key, const QString& value);
Q_INVOKABLE int activeTimelineIndex();
int activeWallpaperCounter() const { return m_activeWallpaperCounter; }
int activeWidgetsCounter() const { return m_activeWidgetsCounter; }

View File

@ -6,6 +6,7 @@
#include <QTimer>
#include <memory>
#include "ScreenPlay/monitorlistmodel.h"
#include "ScreenPlay/wallpapertimelinesection.h"
namespace ScreenPlay {
@ -19,6 +20,8 @@ public:
std::optional<std::shared_ptr<WallpaperTimelineSection>> activeWallpaperSectionByAppID(const QString& appID);
std::shared_ptr<WallpaperTimelineSection> findActiveWallpaperTimelineSection();
std::shared_ptr<WallpaperTimelineSection> findTimelineForCurrentTime();
void startup();
bool addTimelineFromSettings(const QJsonObject& timelineObj);
bool deactivateCurrentTimeline();
bool moveTimelineAt(const int index, const QString identifier, const float relativePosition, QString positionTimeString);
@ -26,24 +29,38 @@ public:
bool addTimelineAt(const int index, const float reltiaveLinePosition, QString identifier);
bool removeTimelineAt(const int index);
QCoro::Task<bool> removeAllTimlineSections();
QCoro::Task<bool> removeAllWallpaperFromActiveTimlineSections();
QCoro::Task<bool> removeWallpaperAt(
const int timelineIndex,
const QString timelineIdentifier,
const int monitorIndex);
void updateIndices();
void printTimelines();
bool setWallpaperAtTimelineIndex(WallpaperData wallpaperData,
QCoro::Task<bool> setWallpaperAtTimelineIndex(
WallpaperData wallpaperData,
const int timelineIndex,
const QString& identifier);
QJsonArray initialSectionsList();
QJsonArray timelineWallpaperList();
void setGlobalVariables(const std::shared_ptr<GlobalVariables>& globalVariables);
void setSettings(const std::shared_ptr<Settings>& settings);
void startupFirstTimeline();
void setMonitorListModel(const std::shared_ptr<MonitorListModel>& monitorListModel);
void updateMonitorListModelData(const int selectedTimelineIndex);
private slots:
void checkActiveWallpaperTimeline();
signals:
void requestSaveProfiles();
void activeWallpaperCountChanged(const int count);
private:
std::optional<std::shared_ptr<WallpaperTimelineSection>> activeWallpaperSection(const int timelineIndex, const QString timelineIdentifier);
private:
QVector<std::shared_ptr<WallpaperTimelineSection>> m_wallpaperTimelineSectionsList;
std::shared_ptr<MonitorListModel> m_monitorListModel;
// We use a 24 hour system
const QString m_timelineTimeFormat = "hh:mm:ss";
QTimer m_contentTimer;

View File

@ -2,17 +2,17 @@
#pragma once
#include "ScreenPlayUtil/contenttypes.h"
#include <QDebug>
#include <QDir>
#include <QFileInfoList>
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonObject>
#include <QObject>
#include <QProcess>
#include <QString>
#include <QStringList>
#include "ScreenPlayUtil/contenttypes.h"
#include <QUuid>
namespace ScreenPlay {
@ -30,6 +30,5 @@ struct WallpaperData {
QJsonObject serialize() const;
static std::optional<WallpaperData> loadWallpaperConfig(const QJsonObject& wallpaperObj);
};
}

View File

@ -45,15 +45,22 @@ public:
std::shared_ptr<GlobalVariables> globalVariables;
std::shared_ptr<Settings> settings;
public:
// Check if currentTime falls within the timeline section
bool containsTime(const QTime& time) const;
QJsonObject serialize() const;
bool activateTimeline();
QCoro::Task<bool> deactivateTimeline();
QCoro::Task<bool> deactivateTimeline();
QCoro::Task<bool> removeWallpaper(const int monitorIndex);
private slots:
void updateActiveWallpaperCounter();
private:
std::optional<std::shared_ptr<ScreenPlayWallpaper>> wallpaperByMonitorIndex(const int index);
signals:
void requestSaveProfiles();
void activeWallpaperCountChanged(const int count);
};
}

View File

@ -8,64 +8,57 @@ import QtCore as QCore
ApplicationWindow {
id: root
color: Material.theme === Material.Dark ? Qt.darker(
Material.background) : Material.background
color: Material.theme === Material.Dark ? Qt.darker(Material.background) : Material.background
// Set visible if the -silent parameter was not set (see app.cpp end of constructor).
visible: false
width: 1400
height: 810
minimumHeight: 450
minimumWidth: 1050
Component.onCompleted: {
// App is now a qml singleton to fix QtC autocompletion.
// This also now means we have to make sure to init it here
// and do _not_ access any other properties before we called init.
App.init()
setTheme(App.settings.theme)
App.init();
setTheme(App.settings.theme);
if (!App.settings.silentStart) {
App.showDockIcon(true)
root.show()
App.showDockIcon(true);
root.show();
}
baseLoader.setSource("qrc:/qml/ScreenPlayApp/qml/MainApp.qml")
const isSteamVersion = App.globalVariables.isSteamVersion()
let platform = ""
baseLoader.setSource("qrc:/qml/ScreenPlayApp/qml/MainApp.qml");
const isSteamVersion = App.globalVariables.isSteamVersion();
let platform = "";
if (isSteamVersion)
platform = qsTr("Steam")
const isProVersion = App.globalVariables.isProVersion()
let featureLevel = ""
platform = qsTr("Steam");
const isProVersion = App.globalVariables.isProVersion();
let featureLevel = "";
if (isProVersion)
featureLevel = qsTr("Pro")
const isUltraVersion = App.globalVariables.isUltraVersion()
featureLevel = qsTr("Pro");
const isUltraVersion = App.globalVariables.isUltraVersion();
if (isUltraVersion)
featureLevel = qsTr("Ultra")
root.title = "ScreenPlay - v" + App.version() + " " + featureLevel + " " + platform
featureLevel = qsTr("Ultra");
root.title = "ScreenPlay - v" + App.version() + " " + featureLevel + " " + platform;
}
Connections {
target: App
function onRequestExit(){
Qt.exit(0)
function onRequestExit() {
Qt.exit(0);
}
}
function setTheme(theme) {
switch (theme) {
case Settings.Theme.System:
root.Material.theme = Material.System
break
root.Material.theme = Material.System;
break;
case Settings.Theme.Dark:
root.Material.theme = Material.Dark
break
root.Material.theme = Material.Dark;
break;
case Settings.Theme.Light:
root.Material.theme = Material.Light
break
root.Material.theme = Material.Light;
break;
}
}
@ -74,7 +67,7 @@ ApplicationWindow {
Material.accent: Material.color(Material.Orange)
onVisibilityChanged: {
if (root.visibility !== 2)
return
return;
}
QCore.Settings {
@ -82,23 +75,21 @@ ApplicationWindow {
}
onClosing: close => {
close.accepted = false
if (App.screenPlayManager.activeWallpaperCounter === 0
&& App.screenPlayManager.activeWidgetsCounter === 0) {
App.exit()
}
const alwaysMinimize = settings.value("alwaysMinimize", null)
if (alwaysMinimize === null) {
console.error(
"Unable to retreive alwaysMinimize setting")
}
if (alwaysMinimize === "true") {
root.hide()
App.showDockIcon(false)
return
}
baseLoader.item.openExitDialog()
}
close.accepted = false;
if (App.screenPlayManager.activeWallpaperCounter === 0 && App.screenPlayManager.activeWidgetsCounter === 0) {
App.exit();
}
const alwaysMinimize = settings.value("alwaysMinimize", null);
if (alwaysMinimize === null) {
console.error("Unable to retreive alwaysMinimize setting");
}
if (alwaysMinimize === "true") {
root.hide();
App.showDockIcon(false);
return;
}
baseLoader.item.openExitDialog();
}
Loader {
id: baseLoader

View File

@ -6,10 +6,13 @@ Item {
property real lineWidth: 1
property real linePosition: (root.x / lineWidth).toFixed(4)
property string timeString: {
const normalized = root.x / root.lineWidth; // Your existing normalization
const normalized = root.x / root.lineWidth;
// Your existing normalization
let totalHours = normalized * 24;
let hours = Math.floor(totalHours); // Gets the whole hour part
let minutes = Math.round((totalHours - hours) * 60); // Calculates the minutes
let hours = Math.floor(totalHours);
// Gets the whole hour part
let minutes = Math.round((totalHours - hours) * 60);
// Calculates the minutes
// Check if minutes rolled over to 60, adjust hours and minutes accordingly
if (minutes === 60) {
hours += 1; // Increment hours by 1
@ -35,15 +38,18 @@ Item {
width: 20
height: width
Rectangle {
id: handleCircle
visible: !root.isLast
radius: width
color: dragHandler.active ? "orange" : "white"
anchors.fill: parent
width: 20
height: width
}
// To block
MouseArea {
hoverEnabled: true
propagateComposedEvents: false
anchors.centerIn: parent
width: 50
height: 50
}
@ -54,7 +60,7 @@ Item {
color: "white"
visible: !root.isLast
anchors {
horizontalCenter: parent.horizontalCenter
horizontalCenter: handleCircle.horizontalCenter
bottom: parent.bottom
bottomMargin: -20
}

View File

@ -6,7 +6,8 @@ Rectangle {
z: selected ? 99 : 0
property int index: 0
property string identifier
property bool selected: false
property bool selected: false // User selected
property bool isActive: false // Active based on time
property bool isLast: false
property alias text: text.text
@ -24,6 +25,22 @@ Rectangle {
}
}
Rectangle {
opacity: root.isActive ? 1 : 0
color: "gold"
height: root.height
anchors {
right: parent.right
left: parent.left
bottom: parent.bottom
}
Behavior on opacity {
NumberAnimation {
duration: 200
}
}
}
Rectangle {
visible: root.selected
color: "gold"
@ -45,10 +62,17 @@ Rectangle {
top: parent.bottom
topMargin: 0
}
Behavior on color {
ColorAnimation {
duration: 200
}
}
}
Rectangle {
id: background
id: monitorBackground
width: 70
height: 48
radius: 5
@ -60,6 +84,13 @@ Rectangle {
top: indicatorLineVertical.bottom
topMargin: -1
}
Behavior on color {
ColorAnimation {
duration: 200
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
@ -80,8 +111,8 @@ Rectangle {
font.pointSize: 10
anchors {
left: background.right
bottom: background.top
left: monitorBackground.right
bottom: monitorBackground.top
margins: -20
}
}

View File

@ -14,23 +14,31 @@ Control {
leftPadding: 20
rightPadding: 20
property int activeTimelineIndex: -1
property int length: timeLine.sectionsList.length
function getActiveTimeline() {
return timeLine.sectionsList[root.activeTimelineIndex]
}
// User selected
property int selectedTimelineIndex: -1
property var selectedTimeline: timeline.sectionsList[root.selectedTimelineIndex]
property int length: timeline.sectionsList.length
function removeAll() {
timeLine.removeAll()
timeline.removeAll();
}
function printTimelines() {
print("################# qml:")
for (var i = 0; i < timeLine.sectionsList.length; i++) {
print(timeLine.sectionsList[i].index,
timeLine.sectionsList[i].identifier,
timeLine.sectionsList[i].relativeLinePosition)
function reset() {
timeline.reset();
}
LoggingCategory {
id: timelineLogging
name: "timeline"
defaultLogLevel: LoggingCategory.Debug
}
Connections {
target: App.screenPlayManager
function onPrintQmlTimeline() {
console.debug(timelineLogging, "################# qml:");
for (var i = 0; i < timeline.sectionsList.length; i++) {
console.debug(timelineLogging, timeline.sectionsList[i].index, timeline.sectionsList[i].identifier, timeline.sectionsList[i].relativeLinePosition);
}
}
}
@ -40,60 +48,71 @@ Control {
property string identifier
property int index: 0
property real relativeLinePosition: lineHandle.linePosition
onRelativeLinePositionChanged: print("relativelinepos: ",
relativeLinePosition)
onRelativeLinePositionChanged: console.debug("relativelinepos: ", relativeLinePosition)
property LineHandle lineHandle
property LineIndicator lineIndicator
}
}
contentItem: Item {
id: timeLine
id: timeline
height: 160
implicitWidth: 600
property var sectionsList: []
property var lineColors: ["#1E88E5", "#00897B", "#43A047", "#C0CA33", "#FFB300", "#FB8C00", "#F4511E", "#E53935", "#D81B60", "#8E24AA", "#5E35B1", "#3949AB"]
onWidthChanged: timeLine.updatePositions()
property var initialSectionsList: []
Component.onCompleted: {
let sectionObects = App.screenPlayManager.initialSectionsList()
for (let sectionObject in sectionObects) {
initialSectionsList.push(sectionObects[sectionObject])
onWidthChanged: timeline.updatePositions()
Component.onCompleted: reset()
Timer {
running: true
repeat: true
interval: 500
onTriggered: {
const activeTimelineIndex = App.screenPlayManager.activeTimelineIndex();
if (activeTimelineIndex === -1) {
return;
}
for (var i = 0; i < timeline.sectionsList.length; i++) {
let section = timeline.sectionsList[i];
section.lineIndicator.isActive = (activeTimelineIndex === i);
}
}
}
function reset() {
removeAll();
let initialSectionsList = App.screenPlayManager.initialSectionsList();
if (App.globalVariables.isBasicVersion()) {
if (initialSectionsList.length > 1) {
console.error(timelineLogging, "Invalid section list count for basic version");
// Create dummy
addSection("INVALID", 1);
}
return;
}
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)
for (var i = 0; i < timeLine.sectionsList.length; i++) {
console.debug(timelineLogging, "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()
console.debug(timelineLogging, "remove index ", i);
let section = timeline.sectionsList[i];
section.lineHandle.destroy();
section.lineIndicator.destroy();
section.destroy();
}
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)
})
timeline.sectionsList = [];
root.selectedTimelineIndex = -1;
}
// IMPORTANT: The new element is always on the left. The first
@ -101,215 +120,208 @@ 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)
console.debug(timelineLogging, "stopPosition", stopPosition);
// Make sure to limit float precision
const fixedStopPosition = stopPosition
print("addSection at: ", fixedStopPosition)
const fixedStopPosition = stopPosition;
console.debug(timelineLogging, "addSection at: ", fixedStopPosition);
if (stopPosition < 0 || fixedStopPosition > 1) {
console.error("Invalid position:", fixedStopPosition)
return
console.error(timelineLogging, "Invalid position:", fixedStopPosition);
return;
}
let sectionObject = sectionComp.createObject(timeLine, {
"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
let sectionObject = sectionComp.createObject(timeline, {
"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.debug(timelineLogging, "Addsection:", index);
createSection(index, fixedStopPosition, sectionObject, identifier);
updatePositions();
return sectionObject;
}
function createSection(index, stopPosition, section, identifier) {
console.log("Adding at:", index, stopPosition, identifier)
console.debug(timelineLogging, "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(timelineLogging, 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(timelineLogging, 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]
for (var i = 0; i < timeline.sectionsList.length; i++) {
if (timeline.sectionsList[i].lineHandle === lineHandle)
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
console.debug(timelineLogging, lineHandle.linePosition);
console.error(timelineLogging, "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
function lineIndicatorSelected(selectedTimelineIndex) {
console.debug(timelineLogging, "selectedTimelineIndex:", selectedTimelineIndex, "section cout: ", timeline.sectionsList.length);
for (var i = 0; i < timeline.sectionsList.length; i++) {
if (i === selectedTimelineIndex) {
timeline.sectionsList[i].lineIndicator.selected = true;
continue;
}
timeLine.sectionsList[i].lineIndicator.selected = false
timeline.sectionsList[i].lineIndicator.selected = false;
}
root.activeTimelineIndex = activeTimelineIndex
root.selectedTimelineIndex = selectedTimelineIndex;
App.screenPlayManager.setSelectedTimelineIndex(selectedTimelineIndex);
}
// We must update all indexes when removing/adding an element
function updateIndicatorIndexes() {
if (timeLine.sectionsList === null
|| timeLine.sectionsList === undefined)
return
timeLine.sectionsList.sort(function (a, b) {
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
//print("updateIndicatorIndexes:", timeLine.sectionsList[i].index, timeLine.sectionsList[i].relativeLinePosition)
if (timeline.sectionsList === null || timeline.sectionsList === undefined)
return;
timeline.sectionsList.sort(function (a, b) {
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;
//console.debug("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
console.debug(timelineLogging, timeline.stopPositionList);
console.debug(timelineLogging, 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
for (var i = 0; i < timeline.sectionsList.length; i++) {
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
if (i === timeLine.sectionsList.length - 1) {
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)
//timeline.sectionsList[i].relativeLinePosition =prevPos / timeline.width
// console.debug("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
// print(section.relativeLinePosition, section.lineHandle.lineMinimum, section.lineHandle.lineMaximum)
for (var j = 0; j < timeline.sectionsList.length; j++) {
let section = timeline.sectionsList[j];
section.relativeLinePosition = section.lineHandle.linePosition;
// console.debug(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
if (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)
for (var i = 0; i < timeline.sectionsList.length; 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
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;
}
}
function updateIndicatorPositions() {
for (var i = 0; i < timeLine.sectionsList.length; i++) {
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
for (var i = 0; i < timeline.sectionsList.length; i++) {
const lineIndicator = timeline.sectionsList[i].lineIndicator;
//console.debug(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;
}
}
// https://stackoverflow.com/a/3885844
function isFloat(n) {
return n === +n && n !== (n | 0)
return n === +n && n !== (n | 0);
}
Rectangle {
@ -332,13 +344,10 @@ 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: 0
x: addHandleWrapper.width * (currentSeconds / totalSeconds)
@ -347,15 +356,9 @@ 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,14 +375,22 @@ Control {
}
RowLayout {
anchors.fill: parent
height: 30
uniformCellSizes: true
anchors {
top: parent.top
right: parent.right
left: parent.left
leftMargin: -5
}
Repeater {
model: 24
model: 25
Item {
width: 20
height: 60
height: 30
required property int index
Text {
id: txtHours
color: "gray"
text: index
anchors {
@ -390,9 +401,9 @@ Control {
Rectangle {
color: "gray"
width: 1
height: 5
height: 10
anchors {
horizontalCenter: parent.horizontalCenter
horizontalCenter: txtHours.horizontalCenter
bottom: parent.bottom
}
}
@ -403,15 +414,18 @@ 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)
if (App.globalVariables.isBasicVersion()) {
screenPlayProView.open();
return;
}
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);
}
ScreenPlayProPopup {
id: screenPlayProView
}
x: hoverHandler.point.position.x - width * .5
@ -436,23 +450,49 @@ Control {
top: addHandleWrapper.bottom
}
}
Item {
Rectangle {
height: 18
width: 5
color: "#757575"
width: 2
anchors {
right: parent.left
top: addHandleWrapper.bottom
topMargin: -9
verticalCenter: lineIndicatorWrapper.verticalCenter
}
}
Rectangle {
height: 18
width: 5
width: 2
color: "#757575"
anchors {
right: parent.right
top: addHandleWrapper.bottom
topMargin: -9
verticalCenter: lineIndicatorWrapper.verticalCenter
}
}
ToolButton {
text: "❌ Reset" //qsTr("Remove all timeline ranges")
z: 99
anchors {
right: parent.right
top: parent.top
}
onClicked: {
timeline.removeAll();
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);
});
}
anchors {
right: parent.right
top: parent.top
topMargin: -height
}
}
}

View File

@ -19,6 +19,7 @@ Util.Popup {
height: 768
onOpened: {
monitorSelection.selectMonitorAt(0);
timeline.reset();
}
background: Rectangle {
anchors.fill: parent
@ -72,6 +73,7 @@ Util.Popup {
}
Timeline {
id: timeline
Layout.fillWidth: true
Layout.fillHeight: true
}
@ -123,8 +125,6 @@ Util.Popup {
width: parent.width * 0.9
multipleMonitorsSelectable: false
monitorWithoutContentSelectable: false
availableWidth: width - 20
availableHeight: 150
onRequestProjectSettings: function (index, installedType, appID) {
if (installedType === Util.ContentTypes.InstalledType.VideoWallpaper) {
videoControlWrapper.state = "visible";

View File

@ -13,7 +13,6 @@ Rectangle {
property bool monitorWithoutContentSelectable: true
property bool multipleMonitorsSelectable: false
property bool isSelected: false
// We preselect the main monitor
property var activeMonitors: []
property alias background: root.color
property alias bgRadius: root.radius
@ -22,6 +21,11 @@ Rectangle {
resize();
selectOnly(0);
}
LoggingCategory {
id: logger
name: "MonitorSelection"
defaultLogLevel: LoggingCategory.Debug
}
signal requestProjectSettings(var index, var installedType, var appID)
@ -50,8 +54,6 @@ Rectangle {
if (rp.itemAt(i).isSelected)
root.activeMonitors.push(rp.itemAt(i).index);
}
// Must be called manually. When QML properties are getting altered in js the
// property binding breaks
root.activeMonitorsChanged();
root.isSelected = root.activeMonitors.length > 0;
return root.activeMonitors;
@ -68,42 +70,45 @@ Rectangle {
}
function resize() {
print("resize");
var absoluteDesktopSize = App.monitorListModel.absoluteDesktopSize();
var isWidthGreaterThanHeight = false;
var windowsDelta = 0;
if (absoluteDesktopSize.width < absoluteDesktopSize.height) {
windowsDelta = absoluteDesktopSize.width / absoluteDesktopSize.height;
isWidthGreaterThanHeight = false;
} else {
windowsDelta = absoluteDesktopSize.height / absoluteDesktopSize.width;
isWidthGreaterThanHeight = true;
}
if (rp.count === 1)
availableWidth = availableWidth * 0.66;
var dynamicHeight = availableWidth * windowsDelta;
var dynamicWidth = availableHeight * windowsDelta;
// Delta (height/width)
var monitorHeightRationDelta = 0;
var monitorWidthRationDelta = 0;
if (isWidthGreaterThanHeight) {
monitorHeightRationDelta = dynamicHeight / absoluteDesktopSize.height;
monitorWidthRationDelta = availableWidth / absoluteDesktopSize.width;
} else {
monitorHeightRationDelta = availableHeight / absoluteDesktopSize.height;
monitorWidthRationDelta = dynamicWidth / absoluteDesktopSize.width;
}
console.debug(logger, "MonitorSelection resize started");
// 1. Get the total desktop size
let totalDesktopSize = App.monitorListModel.totalDesktopSize();
console.debug(logger, "Total desktop size:", totalDesktopSize.width, "x", totalDesktopSize.height);
// 2. Get root item dimensions
let rootWidth = root.width;
let rootHeight = root.height;
console.debug(logger, "Root dimensions:", rootWidth, "x", rootHeight);
// 3. Calculate scaling factor
let margin = 10;
let availableWidth = rootWidth - 2 * margin;
let availableHeight = rootHeight - 2 * margin;
let scaleX = availableWidth / totalDesktopSize.width;
let scaleY = availableHeight / totalDesktopSize.height;
let scaleFactor = Math.min(scaleX, scaleY, 1);
// Ensure we don't scale up
console.debug(logger, "Scale factor:", scaleFactor);
// 4. Resize and position repeater items
let scaledWidth = totalDesktopSize.width * scaleFactor;
let scaledHeight = totalDesktopSize.height * scaleFactor;
for (var i = 0; i < rp.count; i++) {
rp.itemAt(i).index = i;
rp.itemAt(i).height = rp.itemAt(i).height * monitorHeightRationDelta;
rp.itemAt(i).width = rp.itemAt(i).width * monitorWidthRationDelta;
rp.itemAt(i).x = rp.itemAt(i).x * monitorWidthRationDelta;
rp.itemAt(i).y = rp.itemAt(i).y * monitorHeightRationDelta;
rp.contentWidth += rp.itemAt(i).width;
rp.contentHeight += rp.itemAt(i).height;
let item = rp.itemAt(i);
if (item) {
item.width = item.geometry.width * scaleFactor;
item.height = item.geometry.height * scaleFactor;
item.x = item.geometry.x * scaleFactor;
item.y = item.geometry.y * scaleFactor;
}
}
rp.contentWidth += 200;
rp.contentHeight += 200;
// 6. Center content within Flickable
flickable.contentWidth = scaledWidth;
flickable.contentHeight = scaledHeight;
console.debug(logger, "MonitorSelection resize completed", flickable.contentWidth, flickable.contentHeight);
}
color: Material.theme === Material.Light ? Material.background : Qt.darker(Material.background)
@ -148,18 +153,11 @@ Rectangle {
onMonitorSelected: function (index) {
root.selectMonitorAt(index);
}
// onRemoveWallpaper: function(index) {
// }
}
}
ScrollBar.vertical: ScrollBar {
policy: ScrollBar.AlwaysOff
snapMode: ScrollBar.SnapOnRelease
}
ScrollBar.horizontal: ScrollBar {
policy: ScrollBar.AlwaysOff
snapMode: ScrollBar.SnapOnRelease
}
}
ToolButton {

View File

@ -26,6 +26,7 @@ Item {
property bool isSelected: false
signal monitorSelected(var index)
signal remoteWallpaper(var index)
onIsSelectedChanged: root.state = isSelected ? "selected" : "default"
onPreviewImageChanged: {
@ -81,11 +82,23 @@ Item {
cursorShape: Qt.PointingHandCursor
onClicked: {
if (monitorWithoutContentSelectable) {
monitorSelected(index);
root.monitorSelected(index);
return;
}
if (root.hasContent && !root.monitorWithoutContentSelectable)
monitorSelected(index);
root.monitorSelected(index);
}
}
ToolButton {
text: "❌"
enabled: root.hasContent && !root.monitorWithoutContentSelectable
visible: enabled
onClicked: root.remoteWallpaper(index)
anchors {
top: parent.top
right: parent.right
}
}
}

View File

@ -18,6 +18,9 @@ Drawer {
background: Rectangle {
color: Material.color(Material.Grey, Material.Shade900)
}
onOpened: {
timeline.reset();
}
property bool hasPreviewGif: false
property var type: ContentTypes.InstalledType.QMLWallpaper
@ -25,27 +28,29 @@ Drawer {
function setInstalledDrawerItem(folderName, type) {
// Toggle sidebar if clicked on the same content twice
if (root.contentFolderName === folderName)
return;
// Toggle drawer if clicked on the same content twice
if (root.contentFolderName === folderName) {
if (root.visible) {
root.close();
return;
}
}
if (!App.util.isWallpaper(type)) {
return;
}
print("setInstalledDrawerItem", root.contentFolderName, folderName, typeof (folderName), type);
root.contentFolderName = folderName;
root.type = type;
print("setInstalledDrawerItem", folderName,typeof(folderName), type);
if (type === ContentTypes.InstalledType.VideoWallpaper)
installedDrawerWrapper.state = "wallpaper";
else
installedDrawerWrapper.state = "scene";
root.open();
}
// This is used for removing wallpaper. We need to clear
// the preview image/gif so we can release the file for deletion.
function clear() {
root.close();
root.contentFolderName = "";
root.type = ContentTypes.InstalledType.Unknown;
@ -56,11 +61,10 @@ Drawer {
}
onContentFolderNameChanged: {
if (root.contentFolderName === ""){
console.error("empty folder name")
return
if (root.contentFolderName === "") {
console.error("empty folder name");
return;
}
const item = App.installedListModel.get(root.contentFolderName);
print(root.contentFolderName);
txtHeadline.text = item.m_title;
@ -108,22 +112,6 @@ Drawer {
Layout.topMargin: 50
Layout.fillWidth: true
Layout.fillHeight: true
Connections {
target: App.screenPlayManager
function onPrintQmlTimeline() {
timeline.printTimelines();
}
}
ToolButton {
text: "❌" //qsTr("Remove all timeline ranges")
// enabled: timeline.length > 1
onClicked: timeline.removeAll()
anchors {
right: parent.right
top: parent.top
}
}
}
}
@ -144,11 +132,8 @@ Drawer {
MonitorSelection {
id: monitorSelection
objectName: "monitorSelection"
height: 180
Layout.fillWidth: true
Layout.fillHeight: true
availableWidth: width
availableHeight: height - 20
fontSize: 11
}
}
@ -249,8 +234,8 @@ Drawer {
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
objectName: "btnLaunchContent"
text: qsTr("Set Wallpaper");
// enabled: App.util.isWidget(root.type) && activeMonitors.length > 0 ? true : monitorSelection.isSelected
text: qsTr("Set Wallpaper")
enabled: monitorSelection.isSelected && timeline.selectedTimelineIndex > -1
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_plus.svg"
icon.color: "white"
font.pointSize: 12
@ -281,9 +266,18 @@ Drawer {
root.close();
return;
}
const activeTimeline = timeline.getActiveTimeline();
const selectedTimeline = timeline.selectedTimeline;
if (selectedTimeline === undefined) {
console.error("No active timeline");
return;
}
const file = item.m_file;
let success = App.screenPlayManager.setWallpaperAtTimelineIndex(root.type, absoluteStoragePath, previewImage, file, activeMonitors, timeline.activeTimelineIndex, activeTimeline.identifier, true);
let success = App.screenPlayManager.setWallpaperAtTimelineIndex(root.type, absoluteStoragePath, previewImage, file, activeMonitors, selectedTimeline.index, selectedTimeline.identifier, true).then(result => {
if (!result.success) {
console.error("setWallpaperAtTimelineIndex failed");
return;
}
});
}
root.close();
monitorSelection.reset();

View File

@ -9,6 +9,7 @@
#include <QGuiApplication>
#include <QDebug>
#include <QRandomGenerator>
namespace ScreenPlay {
@ -33,11 +34,33 @@ namespace ScreenPlay {
MonitorListModel::MonitorListModel(QObject* parent)
: QAbstractListModel(parent)
{
loadMonitors();
auto* guiAppInst = dynamic_cast<QGuiApplication*>(QGuiApplication::instance());
connect(guiAppInst, &QGuiApplication::screenAdded, this, &MonitorListModel::screenAdded);
connect(guiAppInst, &QGuiApplication::screenRemoved, this, &MonitorListModel::screenRemoved);
// Setup 1: Two Full HD monitors
m_mockMonitorList.append({ Monitor(0, QRect(0, 0, 1920, 1080)),
Monitor(1, QRect(1920, 0, 1920, 1080)) });
// Setup 2: One 4K monitor and one Full HD above
m_mockMonitorList.append({ Monitor(0, QRect(0, 0, 3840, 2160)),
Monitor(1, QRect((-3840 / 2), 3840, 1920, 1080)) });
// Setup 3: One WQHD and one Full HD
m_mockMonitorList.append({ Monitor(0, QRect(0, 0, 2560, 1440)),
Monitor(1, QRect(2560, 0, 1920, 1080)) });
// Setup 4: Three Full HD monitors (two horizontal, one vertical)
m_mockMonitorList.append({ Monitor(0, QRect(0, 0, 1920, 1080)),
Monitor(1, QRect(1920, 0, 1920, 1080)),
Monitor(2, QRect(3840, 0, 1080, 1920)) });
// Setup 5: One ultrawide and one regular monitor
m_mockMonitorList.append({ Monitor(0, QRect(0, 0, 3440, 1440)),
Monitor(1, QRect(3440, 0, 1920, 1080)) });
loadMonitors();
}
/*!
@ -79,40 +102,23 @@ QVariant MonitorListModel::data(const QModelIndex& index, int role) const
return QVariant();
}
auto roleEnum = static_cast<MonitorRole>(role);
if (row > rowCount())
return {};
return QVariant();
switch (roleEnum) {
case MonitorRole::AppID:
return 1;
// if (m_monitorList.at(row).m_activeWallpaper) {
// return m_monitorList.at(row).m_activeWallpaper->appID();
// } else {
// return QVariant("");
// }
return m_monitorList.at(row).m_appID;
case MonitorRole::Index:
return m_monitorList.at(row).m_index;
case MonitorRole::Geometry:
return m_monitorList.at(row).m_geometry;
case MonitorRole::InstalledType:
// if (m_monitorList.at(row).m_activeWallpaper) {
// return static_cast<int>(m_monitorList.at(row).m_activeWallpaper->type());
// } else {
return { "" };
// }
return QVariant::fromValue(m_monitorList.at(row).m_installedType);
case MonitorRole::PreviewImage:
// if (m_monitorList.at(row).m_activeWallpaper) {
// QString absolutePath = m_monitorList.at(row).m_activeWallpaper->absolutePath();
// return absolutePath + "/" + m_monitorList.at(row).m_activeWallpaper->previewImage();
// } else {
return QVariant("");
}
return m_monitorList.at(row).m_wallpaperPreviewImage;
}
return QVariant();
}
@ -121,9 +127,27 @@ QVariant MonitorListModel::data(const QModelIndex& index, int role) const
*/
void MonitorListModel::loadMonitors()
{
if (m_useMockMonitors) {
// Generate a random index
const int selectedMockIndex = QRandomGenerator::global()->bounded(m_mockMonitorList.size());
const auto& mockMonitorList = m_mockMonitorList[selectedMockIndex];
qDebug() << "Using mock" << selectedMockIndex
<< "of" << m_mockMonitorList.size()
<< " with monitor count:" << mockMonitorList.count();
beginInsertRows(index(rowCount()), rowCount(), rowCount() + mockMonitorList.count() - 1);
// Use the randomly selected mock monitor setup
for (const auto& monitor : mockMonitorList) {
m_monitorList.append(monitor);
qDebug() << "Adding mock monitor: " << monitor.m_index << monitor.m_geometry;
}
endInsertRows();
emit monitorReloadCompleted();
return;
}
#ifdef Q_OS_WIN
QModelIndex index;
auto monitors = WindowsIntegration().getAllMonitors();
// This offset lets us center the monitor selection view in the center
@ -151,13 +175,12 @@ void MonitorListModel::loadMonitors()
y + offsetY,
width,
height);
beginInsertRows(index, m_monitorList.size(), m_monitorList.size());
beginInsertRows(index(rowCount()), m_monitorList.size(), m_monitorList.size());
m_monitorList.append(Monitor { i, geometry });
endInsertRows();
i++;
}
#else
QModelIndex index;
int offsetX = 0;
int offsetY = 0;
@ -178,7 +201,7 @@ void MonitorListModel::loadMonitors()
if (screen->geometry().width() == 0 || screen->geometry().height() == 0)
continue;
beginInsertRows(index, m_monitorList.size(), m_monitorList.size());
beginInsertRows(index(rowCount()), m_monitorList.size(), m_monitorList.size());
m_monitorList.append(Monitor { i, screen->geometry() });
endInsertRows();
}
@ -191,31 +214,22 @@ void MonitorListModel::loadMonitors()
* \brief MonitorListModel::getAbsoluteDesktopSize
* \return
*/
QRect MonitorListModel::absoluteDesktopSize() const
QSize MonitorListModel::totalDesktopSize() const
{
auto* guiAppInst = dynamic_cast<QGuiApplication*>(QGuiApplication::instance());
return guiAppInst->screens().at(0)->availableVirtualGeometry();
QRect totalRect;
for (const auto& monitor : m_monitorList) {
totalRect = totalRect.united(monitor.m_geometry);
}
return totalRect.size();
}
/*!
\brief Sets a shared_ptr to the monitor list. This should be used to set and
remove the shared_ptr.
*/
void MonitorListModel::setWallpaperMonitor(
const std::shared_ptr<WallpaperTimelineSection>& timelineSection, const QVector<int> monitors)
QRect MonitorListModel::absoluteDesktopSize() const
{
m_activeTimelineSection = timelineSection;
for (const int monitor : monitors) {
// m_monitorList[monitor].m_activeWallpaper = wallpaper;
emit dataChanged(
index(monitor, 0),
index(monitor, 0),
QVector<int> {
static_cast<int>(MonitorRole::PreviewImage),
static_cast<int>(MonitorRole::InstalledType),
static_cast<int>(MonitorRole::AppID) });
QRect totalRect;
for (const auto& monitor : m_monitorList) {
totalRect = totalRect.united(monitor.m_geometry);
}
return totalRect;
}
/*!
@ -243,6 +257,22 @@ void MonitorListModel::reset()
loadMonitors();
}
bool MonitorListModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
if (role == static_cast<int>(MonitorRole::PreviewImage)) {
m_monitorList[index.column()].m_wallpaperPreviewImage = value.toString();
emit dataChanged(index, index, { role });
}
if (role == static_cast<int>(MonitorRole::AppID)) {
m_monitorList[index.column()].m_appID = value.toString();
emit dataChanged(index, index, { role });
}
if (role == static_cast<int>(MonitorRole::InstalledType)) {
m_monitorList[index.column()].m_installedType = static_cast<ContentTypes::InstalledType>(value.toInt());
emit dataChanged(index, index, { role });
}
return true;
}
}
#include "moc_monitorlistmodel.cpp"

View File

@ -26,6 +26,7 @@ ScreenPlayManager::ScreenPlayManager(
m_server = std::make_unique<QLocalServer>();
QObject::connect(m_server.get(), &QLocalServer::newConnection, this, &ScreenPlayManager::newConnection);
QObject::connect(&m_screenPlayTimelineManager, &ScreenPlayTimelineManager::requestSaveProfiles, this, &ScreenPlayManager::requestSaveProfiles);
QObject::connect(&m_screenPlayTimelineManager, &ScreenPlayTimelineManager::activeWallpaperCountChanged, this, &ScreenPlayManager::setActiveWallpaperCounter);
m_server->setSocketOptions(QLocalServer::WorldAccessOption);
if (!m_server->listen("ScreenPlay")) {
qCritical("Could not open Local Socket with the name ScreenPlay!");
@ -56,6 +57,7 @@ void ScreenPlayManager::init(
m_screenPlayTimelineManager.setGlobalVariables(m_globalVariables);
m_screenPlayTimelineManager.setSettings(m_settings);
m_screenPlayTimelineManager.setMonitorListModel(m_monitorListModel);
// Reset to default settings if we are unable to load
// the existing one
@ -68,7 +70,7 @@ void ScreenPlayManager::init(
/*!
\brief Sets the wallpaper at a spesific timeline.
*/
bool ScreenPlayManager::setWallpaperAtTimelineIndex(
QCoro::QmlTask ScreenPlayManager::setWallpaperAtTimelineIndex(
const ScreenPlay::ContentTypes::InstalledType type,
const QString& absolutePath,
const QString& previewImage,
@ -85,20 +87,28 @@ bool ScreenPlayManager::setWallpaperAtTimelineIndex(
wallpaperData.file = file;
wallpaperData.monitors = monitorIndex;
wallpaperData.fillMode = m_settings->videoFillMode();
const bool success = m_screenPlayTimelineManager.setWallpaperAtTimelineIndex(wallpaperData, timelineIndex, identifier);
if (!success) {
qCritical() << "Invalid timeline index or identifier: " << timelineIndex << identifier;
m_screenPlayTimelineManager.printTimelines();
emit printQmlTimeline();
return false;
}
return QCoro::QmlTask([this, wallpaperData, timelineIndex, identifier]() -> QCoro::Task<Result> {
if (timelineIndex < 0 || identifier.isEmpty()) {
// We do not start the wallpaper here, but let
// ScreenPlayTimelineManager::checkActiveWallpaperTimeline decide
// if the wallpaper
emit requestSaveProfiles();
return true;
co_return Result { false };
}
const bool success = co_await m_screenPlayTimelineManager.setWallpaperAtTimelineIndex(wallpaperData, timelineIndex, identifier);
if (!success) {
qCritical() << "Invalid timeline index or identifier: " << timelineIndex << identifier;
m_screenPlayTimelineManager.printTimelines();
emit printQmlTimeline();
co_return Result { success };
}
// We do not start the wallpaper here, but let
// ScreenPlayTimelineManager::checkActiveWallpaperTimeline decide
// if the wallpaper
emit requestSaveProfiles();
co_return Result { success };
}());
}
/*!
@ -147,37 +157,23 @@ bool ScreenPlayManager::startWidget(
return true;
}
void ScreenPlayManager::setSelectedTimelineIndex(const int selectedTimelineIndex)
{
m_screenPlayTimelineManager.updateMonitorListModelData(selectedTimelineIndex);
}
/*!
\brief Removes all wallpaper entries in the profiles.json.
*/
bool ScreenPlayManager::removeAllWallpapers(bool saveToProfile)
QCoro::QmlTask ScreenPlayManager::removeAllWallpapers(bool saveToProfile)
{
// TODO
// if (m_screenPlayTimelineManager.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());
// }
// for (const auto& appID : appIDs) {
// if (!removeWallpaper(appID)) {
// return false;
// }
// }
// if (saveToProfile)
// emit requestSaveProfiles();
return true;
return QCoro::QmlTask([this]() -> QCoro::Task<Result> {
// call with coro
const bool success = co_await m_screenPlayTimelineManager.removeAllWallpaperFromActiveTimlineSections();
qDebug() << "Task: removeAllWallpaperFromActiveTimlineSections" << success;
// emit requestSaveProfiles();
co_return Result { success };
}());
}
/*!
@ -212,18 +208,16 @@ bool ScreenPlayManager::removeAllWidgets(bool saveToProfile)
given monitor index and then closes the sdk connection, removes the entries in the
monitor list model and decreases the active wallpaper counter property of ScreenPlayManager.
*/
bool ScreenPlayManager::removeWallpaperAt(int index)
QCoro::QmlTask ScreenPlayManager::removeWallpaperAt(int timelineIndex, QString timelineIdentifier, int monitorIndex)
{
if (auto appID = m_monitorListModel->getAppIDByMonitorIndex(index)) {
if (removeWallpaper(*appID)) {
emit requestSaveProfiles();
return true;
}
}
qWarning() << "Could not remove Wallpaper at index:" << index;
return false;
return QCoro::QmlTask([this, timelineIndex, timelineIdentifier, monitorIndex]() -> QCoro::Task<Result> {
// call with coro
const bool success = co_await m_screenPlayTimelineManager.removeWallpaperAt(timelineIndex, timelineIdentifier, monitorIndex);
qDebug() << "Task: removeAllWallpaperFromActiveTimlineSections" << success;
// crash? mit requestSaveProfiles();
co_return Result { success };
}());
}
/*!
@ -531,6 +525,16 @@ bool ScreenPlayManager::setWallpaperValue(const QString& appID, const QString& k
return false;
}
int ScreenPlayManager::activeTimelineIndex()
{
std::shared_ptr<WallpaperTimelineSection> activeTimelineSection = m_screenPlayTimelineManager.findActiveWallpaperTimelineSection();
if (!activeTimelineSection) {
qCritical() << "setWallpaperValue failed, because no active timeline section was found";
return -1;
}
return activeTimelineSection->index;
}
/*!
\brief Saves a given wallpaper \a newProfileObject to a \a profileName. We ignore the profileName argument
because we currently only support one profile. Returns \c true if successfuly saved to profiles.json, otherwise \c false.
@ -604,6 +608,7 @@ bool ScreenPlayManager::loadProfiles()
QJsonObject wallpaperObj = timelineWallpaper.toObject();
if (!m_screenPlayTimelineManager.addTimelineFromSettings(wallpaperObj)) {
qCritical() << "Unable to add wallpaper timeline";
containsInvalidData = true;
continue;
}
}
@ -618,10 +623,11 @@ bool ScreenPlayManager::loadProfiles()
// The can happen if the user unpluggs a wallpaper but it still exists
// in the profiles.json. For this we save all profiles with now active
// content.
if (containsInvalidData)
if (containsInvalidData) {
saveProfiles();
m_screenPlayTimelineManager.startupFirstTimeline();
} else {
m_screenPlayTimelineManager.startup();
}
return true;
}

View File

@ -6,6 +6,7 @@
#include <QString>
#include <QStringList>
#include <iostream>
#include <ranges>
namespace ScreenPlay {
@ -24,7 +25,7 @@ ScreenPlayTimelineManager::ScreenPlayTimelineManager(
// 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);
m_contentTimer.setInterval(250);
}
/*!
@ -92,32 +93,33 @@ bool ScreenPlayTimelineManager::addTimelineFromSettings(const QJsonObject& timel
}
// TODO check license
auto timelineSection = std::make_shared<WallpaperTimelineSection>();
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);
auto newTimelineSection = std::make_shared<WallpaperTimelineSection>();
QObject::connect(newTimelineSection.get(), &WallpaperTimelineSection::requestSaveProfiles, this, &ScreenPlayTimelineManager::requestSaveProfiles);
QObject::connect(newTimelineSection.get(), &WallpaperTimelineSection::activeWallpaperCountChanged, this, &ScreenPlayTimelineManager::activeWallpaperCountChanged);
newTimelineSection->startTime = startTime;
newTimelineSection->endTime = endTime;
newTimelineSection->settings = m_settings;
newTimelineSection->globalVariables = m_globalVariables;
newTimelineSection->relativePosition = Util().calculateRelativePosition(endTime);
const auto wallpaperList = timelineObj.value("wallpaper").toArray();
for (auto& wallpaper : wallpaperList) {
std::optional<WallpaperData> wallpaperDataOpt = WallpaperData::loadWallpaperConfig(wallpaper.toObject());
if (!wallpaperDataOpt.has_value())
return false;
timelineSection->wallpaperDataList.push_back(wallpaperDataOpt.value());
newTimelineSection->wallpaperDataList.push_back(wallpaperDataOpt.value());
}
// Todo: Should we use addTimelineAt?
timelineSection->index = m_wallpaperTimelineSectionsList.length();
timelineSection->identifier = Util().generateRandomString(4);
newTimelineSection->index = m_wallpaperTimelineSectionsList.length();
newTimelineSection->identifier = Util().generateRandomString(4);
qInfo() << timelineSection->index
<< timelineSection->startTime
<< timelineSection->endTime;
qInfo() << newTimelineSection->index
<< newTimelineSection->startTime
<< newTimelineSection->endTime;
// Todo: Should we use addTimelineAt?
m_wallpaperTimelineSectionsList.append(timelineSection);
return false;
m_wallpaperTimelineSectionsList.append(newTimelineSection);
return true;
}
/*!
@ -181,12 +183,26 @@ void ScreenPlayTimelineManager::checkActiveWallpaperTimeline()
}
}
std::optional<std::shared_ptr<WallpaperTimelineSection>> ScreenPlayTimelineManager::activeWallpaperSection(const int timelineIndex, const QString timelineIdentifier)
{
for (const auto& section : m_wallpaperTimelineSectionsList) {
const bool indexMatches = section->index == timelineIndex;
const bool timelineIdentifierMatches = section->identifier == timelineIdentifier;
if (indexMatches && timelineIdentifierMatches) {
return section;
}
}
qCritical() << "No matching timeline for index:" << timelineIndex << "timelineIdentifier: " << timelineIdentifier;
return nullptr;
}
void ScreenPlayTimelineManager::setSettings(const std::shared_ptr<Settings>& settings)
{
m_settings = settings;
}
void ScreenPlayTimelineManager::startupFirstTimeline()
void ScreenPlayTimelineManager::startup()
{
std::shared_ptr<WallpaperTimelineSection> currentTimeline = findTimelineForCurrentTime();
if (!currentTimeline) {
@ -194,6 +210,31 @@ void ScreenPlayTimelineManager::startupFirstTimeline()
return;
}
currentTimeline->activateTimeline();
m_contentTimer.start();
}
void ScreenPlayTimelineManager::setMonitorListModel(const std::shared_ptr<MonitorListModel>& monitorListModel)
{
m_monitorListModel = monitorListModel;
}
void ScreenPlayTimelineManager::updateMonitorListModelData(const int selectedTimelineIndex)
{
auto selectedTimeline = m_wallpaperTimelineSectionsList | std::views::drop(selectedTimelineIndex) | std::views::take(1);
// Clear current list model. This is needed to make sure
// that we do not show any old active wallpaper
m_monitorListModel->reset();
if (!selectedTimeline.empty()) {
auto& timeline = selectedTimeline.front();
for (const auto& wallpaper : timeline->wallpaperDataList) {
const auto previewImg = wallpaper.absolutePath + "/" + wallpaper.previewImage;
m_monitorListModel->setData(m_monitorListModel->index(0, wallpaper.monitors.first()), previewImg, (int)MonitorListModel::MonitorRole::PreviewImage);
}
} else {
qCritical() << "No selectedTimelineIndex found" << selectedTimelineIndex;
}
}
void ScreenPlayTimelineManager::setGlobalVariables(const std::shared_ptr<GlobalVariables>& globalVariables)
@ -281,6 +322,7 @@ bool ScreenPlayTimelineManager::addTimelineAt(const int index, const float relti
auto newTimelineSection = std::make_shared<WallpaperTimelineSection>();
QObject::connect(newTimelineSection.get(), &WallpaperTimelineSection::requestSaveProfiles, this, &ScreenPlayTimelineManager::requestSaveProfiles);
QObject::connect(newTimelineSection.get(), &WallpaperTimelineSection::activeWallpaperCountChanged, this, &ScreenPlayTimelineManager::activeWallpaperCountChanged);
newTimelineSection->settings = m_settings;
newTimelineSection->globalVariables = m_globalVariables;
newTimelineSection->index = index;
@ -332,6 +374,39 @@ QCoro::Task<bool> ScreenPlayTimelineManager::removeAllTimlineSections()
co_return true;
}
/*!
\brief Qml function that removes all wallpaper for the current Timeline section.
*/
QCoro::Task<bool> ScreenPlayTimelineManager::removeAllWallpaperFromActiveTimlineSections()
{
// 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
activeTimelineSection->deactivateTimeline();
activeTimelineSection->wallpaperDataList.clear();
}
co_return true;
}
/*!
\brief Qml function that removes all wallpaper for the current Timeline section.
*/
QCoro::Task<bool> ScreenPlayTimelineManager::removeWallpaperAt(const int timelineIndex, const QString timelineIdentifier, const int monitorIndex)
{
m_contentTimer.stop();
auto updateTimer = qScopeGuard([this] { m_contentTimer.start(); });
auto sectionOpt = activeWallpaperSection(timelineIndex, timelineIdentifier);
if (!sectionOpt)
co_return false;
const bool success = co_await sectionOpt.value()->removeWallpaper(monitorIndex);
co_return success;
}
/*!
\brief Removes a timeline at a given index. Expands the timeline next to it
to fill the space.
@ -405,7 +480,10 @@ void ScreenPlayTimelineManager::printTimelines()
}
}
bool ScreenPlayTimelineManager::setWallpaperAtTimelineIndex(WallpaperData wallpaperData, const int timelineIndex, const QString& identifier)
QCoro::Task<bool> ScreenPlayTimelineManager::setWallpaperAtTimelineIndex(
WallpaperData wallpaperData,
const int timelineIndex,
const QString& identifier)
{
bool found = false;
for (auto& timelineSection : m_wallpaperTimelineSectionsList) {
@ -426,6 +504,9 @@ bool ScreenPlayTimelineManager::setWallpaperAtTimelineIndex(WallpaperData wallpa
if (it != timelineSection->wallpaperDataList.end()) {
// Overwrite the existing wallpaper
*it = wallpaperData;
// TODO: Do not replace but
co_await timelineSection->deactivateTimeline();
timelineSection->activateTimeline();
} else {
// Append the new wallpaper data
timelineSection->wallpaperDataList.push_back(wallpaperData);
@ -436,7 +517,7 @@ bool ScreenPlayTimelineManager::setWallpaperAtTimelineIndex(WallpaperData wallpa
break;
}
}
return found;
co_return found;
}
QJsonArray ScreenPlayTimelineManager::initialSectionsList()

View File

@ -71,22 +71,6 @@ bool WallpaperTimelineSection::activateTimeline()
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<ScreenPlayWallpaper>(
globalVariables,
appID,
@ -100,6 +84,7 @@ bool WallpaperTimelineSection::activateTimeline()
QObject::connect(screenPlayWallpaper.get(), &ScreenPlayWallpaper::requestClose, this, []() {
// , &ScreenPlayManager::removeWallpaper);
});
QObject::connect(screenPlayWallpaper.get(), &ScreenPlayWallpaper::isConnectedChanged, this, &WallpaperTimelineSection::updateActiveWallpaperCounter);
// QObject::connect(screenPlayWallpaper.get(), &ScreenPlayWallpaper::error, this, this, []() {
// // , &ScreenPlayManager::displayErrorPopup);
@ -144,4 +129,44 @@ QCoro::Task<bool> WallpaperTimelineSection::deactivateTimeline()
co_return false;
}
QCoro::Task<bool> WallpaperTimelineSection::removeWallpaper(const int monitorIndex)
{
auto wallpaperOpt = wallpaperByMonitorIndex(monitorIndex);
if (!wallpaperOpt.has_value()) {
qCritical() << "No wallpaper found for monitor index:" << monitorIndex;
co_return false;
}
QTimer timer;
timer.start(250);
const int maxRetries = 30;
wallpaperOpt.value()->close();
for (int i = 1; i <= maxRetries; ++i) {
// Wait for the timer to tick
co_await timer;
if (!wallpaperOpt.value()->isConnected()) {
co_return true;
}
}
co_return false;
}
void WallpaperTimelineSection::updateActiveWallpaperCounter()
{
quint64 activeWallpaperCount = 0;
for (const auto& screenPlayWallpaper : activeWallpaperList) {
if (screenPlayWallpaper->isConnected())
activeWallpaperCount++;
}
emit activeWallpaperCountChanged(activeWallpaperCount);
}
std::optional<std::shared_ptr<ScreenPlayWallpaper>> WallpaperTimelineSection::wallpaperByMonitorIndex(const int monitorIndex)
{
for (const auto& screenPlayWallpaper : activeWallpaperList) {
if (screenPlayWallpaper->monitors().contains(monitorIndex))
return screenPlayWallpaper;
}
return std::nullopt;
}
}

View File

@ -1,11 +1,11 @@
import QtQuick
import QtQuick.Controls
import QtQuick.Controls as QQC
import Qt5Compat.GraphicalEffects
import QtQuick.Controls.Material
import QtQuick.Layouts
import ScreenPlayUtil
Popup {
QQC.Popup {
id: root
property Item modalSource
// Workaround for missing animation on hide

View File

@ -1,9 +1,9 @@
// SPDX-License-Identifier: LicenseRef-EliasSteurerTachiom OR AGPL-3.0-only
#include "ScreenPlayUtil/util.h"
#include "qguiapplication.h"
#include <QDesktopServices>
#include <QFile>
#include <QGuiApplication>
#include <QJsonParseError>
#include <QRandomGenerator>

View File

@ -58,11 +58,10 @@ Rectangle {
return;
}
// For example if background is a solid color
if(Wallpaper.windowsDesktopProperties.wallpaperPath === ""){
if (Wallpaper.windowsDesktopProperties.wallpaperPath === "") {
root.canFadeByWallpaperFillMode = false;
return;
}
imgCover.source = Qt.resolvedUrl("file:///" + Wallpaper.windowsDesktopProperties.wallpaperPath);
switch (Wallpaper.windowsDesktopProperties.wallpaperStyle) {
case 10:

View File

@ -356,7 +356,6 @@ protected:
QVector<int> m_activeScreensList;
QFileSystemWatcher m_fileSystemWatcher;
QTimer m_liveReloadLimiter;
QSysInfo m_sysinfo;
std::unique_ptr<ScreenPlaySDK> m_sdk;
QUrl m_projectSourceFileAbsolute;
ScreenPlay::Video::VideoCodec m_videoCodec = ScreenPlay::Video::VideoCodec::Unknown;