1
0
mirror of https://gitlab.com/kelteseth/ScreenPlay.git synced 2024-10-06 09:17:07 +02:00

WIP: Replace Sidebar with bottom drawer with timeline

This commit is contained in:
Elias Steurer 2024-03-28 12:21:11 +01:00
parent c1a81588d9
commit f9cafc891b
18 changed files with 511 additions and 454 deletions

View File

@ -61,7 +61,7 @@ set(VCPKG_BIN_PATH "${VCPKG_INSTALLED_PATH}/bin")
# Godot Editor # Godot Editor
set(GODOT_VERSION_MAJOR "4") set(GODOT_VERSION_MAJOR "4")
set(GODOT_VERSION_MINOR "2") set(GODOT_VERSION_MINOR "2")
set(GODOT_VERSION_PATCH "") set(GODOT_VERSION_PATCH "1")
set(GODOT_RELEASE_TYPE "stable") set(GODOT_RELEASE_TYPE "stable")
# Use an if statement to check if GODOT_VERSION_PATCH is empty or not # Use an if statement to check if GODOT_VERSION_PATCH is empty or not

View File

@ -1,21 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<body>
<script>
let body = document.getElementsByTagName('body')[0];
body.setAttribute('style', 'margin: 0px;padding: 0px;overflow: hidden;background:black;');
let html = document.getElementsByTagName('html')[0];
html.setAttribute('style', 'margin: 0px;padding: 0px;overflow: hidden;background:black;');
var videoElem = document.createElement('video');
videoElem.setAttribute('width', '100%');
videoElem.setAttribute('height', '100%');
videoElem.setAttribute('id', 'video');
videoElem.muted = true;
videoElem.autoplay = true;
videoElem.loop = true;
document.body.appendChild(videoElem);
</script>
</body>
</html>

View File

@ -13,6 +13,7 @@
#include "monitorlistmodel.h" #include "monitorlistmodel.h"
#include "profilelistmodel.h" #include "profilelistmodel.h"
#include "projectsettingslistmodel.h" #include "projectsettingslistmodel.h"
#include "screenplayprofiles.h"
#include "screenplaywallpaper.h" #include "screenplaywallpaper.h"
#include "screenplaywidget.h" #include "screenplaywidget.h"
#include "settings.h" #include "settings.h"
@ -21,6 +22,21 @@
namespace ScreenPlay { namespace ScreenPlay {
struct Wallpaper {
QString name;
QTime startTime;
QTime endTime;
QString absolutePath;
QString previewImage;
float playbackRate;
float volume;
QString file;
QJsonObject properties;
ContentTypes::InstalledType type;
Video::FillMode fillMode;
QVector<int> monitors;
};
class ScreenPlayManager : public QObject { class ScreenPlayManager : public QObject {
Q_OBJECT Q_OBJECT
QML_ELEMENT QML_ELEMENT
@ -139,11 +155,14 @@ public slots:
private: private:
bool loadProfiles(); bool loadProfiles();
bool loadWidgetConfig(const QJsonObject& widget);
bool loadWallpaperConfig(const QJsonObject& wallpaper);
bool checkIsAnotherScreenPlayInstanceRunning(); bool checkIsAnotherScreenPlayInstanceRunning();
bool removeWallpaper(const QString& appID); bool removeWallpaper(const QString& appID);
bool removeWidget(const QString& appID); bool removeWidget(const QString& appID);
private: private:
ScreenPlayProfiles m_screenPlayProfiles;
std::shared_ptr<GlobalVariables> m_globalVariables; std::shared_ptr<GlobalVariables> m_globalVariables;
std::shared_ptr<MonitorListModel> m_monitorListModel; std::shared_ptr<MonitorListModel> m_monitorListModel;
std::shared_ptr<Settings> m_settings; std::shared_ptr<Settings> m_settings;
@ -161,6 +180,6 @@ private:
QTimer m_saveLimiter; QTimer m_saveLimiter;
const quint16 m_webSocketPort = 16395; const quint16 m_webSocketPort = 16395;
bool loadTimelineWallpaperConfig(const QJsonObject& wallpaperObj);
}; };
} }

View File

@ -17,7 +17,7 @@ TabButton {
ToolButton { ToolButton {
icon.source: control.icon.source icon.source: control.icon.source
icon.color: control.checked ? Material.accentColor : Material.secondaryTextColor icon.color: control.checked ? Material.accentColor : "transparent"
hoverEnabled: false hoverEnabled: false
icon.width: 16 icon.width: 16
icon.height: 16 icon.height: 16
@ -49,6 +49,7 @@ TabButton {
opacity: 0.6 opacity: 0.6
width: parent.width * 0.2 width: parent.width * 0.2
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_open_in_new.svg" icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_open_in_new.svg"
icon.color: "transparent"
icon.width: 16 icon.width: 16
icon.height: 16 icon.height: 16
onClicked: Qt.openUrlExternally(control.openLink) onClicked: Qt.openUrlExternally(control.openLink)

View File

@ -14,7 +14,7 @@ Rectangle {
Text { Text {
id: text id: text
color: "white" color: "white"
text: root.index //text: root.index
anchors{ anchors{
horizontalCenter: parent.horizontalCenter horizontalCenter: parent.horizontalCenter
bottom: parent.bottom bottom: parent.bottom

View File

@ -4,11 +4,11 @@ import QtQuick.Layouts
Control { Control {
id: root id: root
height: 220 height: 160
implicitWidth: 800 implicitWidth: 800
topPadding: 40 topPadding: 20
leftPadding: 40 leftPadding: 20
rightPadding: 40 rightPadding: 20
contentItem: Item { contentItem: Item {
id: timeLine id: timeLine

View File

@ -335,7 +335,7 @@ Item {
modalSource: root.modalSource modalSource: root.modalSource
anchors.centerIn: Overlay.overlay anchors.centerIn: Overlay.overlay
onAccepted: { onAccepted: {
root.sidebar.clear() root.sidebar.close()
if (!App.installedListModel.deinstallItemAt( if (!App.installedListModel.deinstallItemAt(
contextMenu.absoluteStoragePath)) { contextMenu.absoluteStoragePath)) {
console.error("Unable to uninstall item", console.error("Unable to uninstall item",

View File

@ -9,11 +9,14 @@ import ScreenPlayApp
import ScreenPlayUtil import ScreenPlayUtil
import "../Monitors" import "../Monitors"
import "../Components"
Item { Drawer {
id: root id: root
height: 500
property real navHeight modal: false
edge: Qt.BottomEdge
property bool hasPreviewGif: false
property var type: ContentTypes.InstalledType.QMLWallpaper property var type: ContentTypes.InstalledType.QMLWallpaper
property string contentFolderName property string contentFolderName
@ -29,15 +32,13 @@ Item {
// This is used for removing wallpaper. We need to clear // This is used for removing wallpaper. We need to clear
// the preview image/gif so we can release the file for deletion. // the preview image/gif so we can release the file for deletion.
function clear() { function clear() {
root.close()
imagePreview.source = "" imagePreview.source = ""
animatedImagePreview.source = "" animatedImagePreview.source = ""
txtHeadline.text = "" txtHeadline.text = ""
root.state = "inactive" sidebarWrapper.state = "inactive"
} }
width: 400
state: "inactive"
property bool hasPreviewGif: false
onContentFolderNameChanged: { onContentFolderNameChanged: {
const item = App.installedListModel.get(root.contentFolderName) const item = App.installedListModel.get(root.contentFolderName)
txtHeadline.text = item.m_title txtHeadline.text = item.m_title
@ -64,97 +65,109 @@ Item {
function onSetSidebarItem(folderName, type) { function onSetSidebarItem(folderName, type) {
// Toggle sidebar if clicked on the same content twice // Toggle sidebar if clicked on the same content twice
if (root.contentFolderName === folderName if (root.contentFolderName === folderName && root.opened) {
&& root.state !== "inactive") { root.close()
root.state = "inactive"
return return
} }
root.contentFolderName = folderName root.contentFolderName = folderName
root.type = type root.type = type
if (App.util.isWallpaper(root.type)) { if (App.util.isWallpaper(root.type)) {
if (type === ContentTypes.InstalledType.VideoWallpaper) if (type === ContentTypes.InstalledType.VideoWallpaper)
root.state = "activeWallpaper" sidebarWrapper.state = "wallpaper"
else else
root.state = "activeScene" sidebarWrapper.state = "scene"
btnLaunchContent.text = qsTr("Set Wallpaper") btnLaunchContent.text = qsTr("Set Wallpaper")
} else { } else {
root.state = "activeWidget" sidebarWrapper.state = "widget"
btnLaunchContent.text = qsTr("Set Widget") btnLaunchContent.text = qsTr("Set Widget")
} }
root.open()
} }
target: App.util target: App.util
} }
MouseHoverBlocker {} RowLayout {
Rectangle {
anchors.fill: parent
color: Material.theme === Material.Light ? "white" : Material.background
opacity: 0.95
layer.enabled: true
layer.effect: ElevationEffect {
elevation: 4
}
}
Item {
id: sidebarWrapper id: sidebarWrapper
state: "inactive"
spacing: 20
anchors.fill: parent anchors.fill: parent
Item { ColumnLayout {
id: navBackground Layout.fillWidth: true
Layout.fillHeight: true
Layout.leftMargin: 10
spacing: 5
height: navHeight ColumnLayout {
spacing: 5
Layout.fillWidth: true
Layout.preferredHeight: 160
anchors { Text {
top: parent.top Layout.leftMargin: 20
right: parent.right text: qsTr("Select the duration your wallpaper should be visible")
left: parent.left font.family: App.settings.font
verticalAlignment: Text.AlignVCenter
font.pointSize: 11
color: Material.secondaryTextColor
}
Timeline {
Layout.fillWidth: true
Layout.fillHeight: true
}
} }
Rectangle { RowLayout {
anchors.fill: parent spacing: 10
gradient: Gradient { ColumnLayout {
GradientStop { Layout.fillWidth: true
position: 0 Layout.fillHeight: true
color: "transparent" Layout.horizontalStretchFactor: 3
} spacing: 10
GradientStop {
position: 0.1 Text {
color: "#AAffffff" text: qsTr("Select a Monitor to display the content")
font.family: App.settings.font
verticalAlignment: Text.AlignVCenter
font.pointSize: 11
color: Material.secondaryTextColor
} }
GradientStop { MonitorSelection {
position: 1 id: monitorSelection
color: "#ffffff" objectName: "monitorSelection"
height: 200
Layout.fillWidth: true
availableWidth: width
availableHeight: height
fontSize: 11
} }
} }
Item {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.horizontalStretchFactor: 1
}
} }
} }
Item { ColumnLayout {
id: sidebarBackground Layout.preferredWidth: 260
Layout.fillHeight: true
anchors { spacing: 10
top: navBackground.bottom
right: parent.right
bottom: parent.bottom
left: parent.left
}
Rectangle { Rectangle {
id: imageWrapper id: imageWrapper
height: 237
color: "#2b2b2b" color: "#2b2b2b"
anchors.right: parent.right
anchors.rightMargin: 0 Layout.preferredHeight: 180
anchors.left: parent.left Layout.fillWidth: true
anchors.leftMargin: 0 Layout.alignment: Qt.AlignTop
// Do NOT enable async image loading! // Do NOT enable async image loading!
// Otherwhise it will still hold the file // Otherwhise it will still hold the file
@ -220,62 +233,12 @@ Item {
left: parent.left left: parent.left
} }
} }
MouseArea {
id: button
height: 50
width: 50
anchors.top: parent.top
anchors.left: parent.left
cursorShape: Qt.PointingHandCursor
onClicked: root.state = "inactive"
Image {
id: imgBack
source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_arrow_right.svg"
sourceSize: Qt.size(15, 15)
fillMode: Image.PreserveAspectFit
anchors.centerIn: parent
}
}
} }
ColumnLayout { ColumnLayout {
spacing: 20 spacing: 20
Layout.fillWidth: true
anchors { Layout.alignment: Qt.AlignTop
top: imageWrapper.bottom
right: parent.right
left: parent.left
margins: 30
}
ColumnLayout {
Layout.fillWidth: true
Text {
id: txtHeadlineMonitor
height: 20
text: qsTr("Select a Monitor to display the content")
font.family: App.settings.font
verticalAlignment: Text.AlignVCenter
font.pointSize: 11
color: Material.secondaryTextColor
}
MonitorSelection {
id: monitorSelection
objectName: "monitorSelection"
height: 180
Layout.fillWidth: true
availableWidth: width
availableHeight: height
fontSize: 11
}
}
LabelSlider { LabelSlider {
id: sliderVolume id: sliderVolume
@ -365,14 +328,13 @@ Item {
const absoluteStoragePath = item.m_absoluteStoragePath const absoluteStoragePath = item.m_absoluteStoragePath
const previewImage = item.m_preview const previewImage = item.m_preview
if (App.util.isWallpaper(root.type)) { if (App.util.isWallpaper(root.type)) {
if (type === ContentTypes.InstalledType.GodotWallpaper){ if (type === ContentTypes.InstalledType.GodotWallpaper) {
if(!App.globalVariables.isBasicVersion()) { if (App.globalVariables.isBasicVersion()) {
root.state = "inactive" sidebarWrapper.state = "inactive"
return return
} }
} }
let activeMonitors = monitorSelection.getActiveMonitors( let activeMonitors = monitorSelection.getActiveMonitors(
) )
// TODO Alert user to choose a monitor // TODO Alert user to choose a monitor
@ -404,7 +366,7 @@ Item {
1, {}, true) 1, {}, true)
} }
}) })
root.state = "inactive" root.close()
return return
} }
@ -420,230 +382,205 @@ Item {
absoluteStoragePath, absoluteStoragePath,
previewImage, {}, previewImage, {},
true) true)
root.state = "inactive"
root.close()
monitorSelection.reset() monitorSelection.reset()
} }
anchors { Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
bottom: parent.bottom
bottomMargin: 20
horizontalCenter: parent.horizontalCenter
}
} }
} }
ToolButton {
id: button
Layout.alignment: Qt.AlignTop
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_close.svg"
icon.width: 15
icon.height: 15
onClicked: {
root.close()
sidebarWrapper.state = "inactive"
}
}
states: [
State {
name: "inactive"
PropertyChanges {
target: imagePreview
opacity: 0
anchors.topMargin: 20
}
PropertyChanges {
target: animatedImagePreview
opacity: 0
anchors.topMargin: 20
}
},
State {
name: "activeWidget"
PropertyChanges {
target: sliderVolume
visible: false
}
PropertyChanges {
target: monitorSelection
visible: false
enabled: false
}
PropertyChanges {
target: imagePreview
opacity: 1
anchors.topMargin: 0
}
PropertyChanges {
target: animatedImagePreview
opacity: 1
anchors.topMargin: 0
}
PropertyChanges {
target: txtHeadlineMonitor
opacity: 0
}
},
State {
name: "wallpaper"
PropertyChanges {
target: imagePreview
opacity: 1
anchors.topMargin: 0
}
PropertyChanges {
target: animatedImagePreview
opacity: 1
anchors.topMargin: 0
}
PropertyChanges {
target: txtHeadlineMonitor
opacity: 1
}
PropertyChanges {
target: txtComboBoxFillMode
opacity: 1
visible: true
}
PropertyChanges {
target: cbVideoFillMode
opacity: 1
visible: true
}
},
State {
name: "scene"
PropertyChanges {
target: imagePreview
opacity: 1
anchors.topMargin: 0
}
PropertyChanges {
target: animatedImagePreview
opacity: 1
anchors.topMargin: 0
}
PropertyChanges {
target: txtHeadlineMonitor
opacity: 1
}
PropertyChanges {
target: sliderVolume
opacity: 0
visible: false
}
}
]
transitions: [
Transition {
to: "inactive"
from: "*"
reversible: true
NumberAnimation {
targets: [animatedImagePreview, imagePreview]
property: "opacity"
duration: 200
}
NumberAnimation {
targets: [animatedImagePreview, imagePreview]
property: "anchors.topMargin"
duration: 400
}
},
Transition {
to: "widget"
from: "*"
SequentialAnimation {
ParallelAnimation {
NumberAnimation {
targets: [animatedImagePreview, imagePreview]
property: "opacity"
duration: 200
}
NumberAnimation {
targets: [animatedImagePreview, imagePreview]
property: "anchors.topMargin"
duration: 100
}
}
}
},
Transition {
to: "wallpaper"
from: "*"
SequentialAnimation {
ParallelAnimation {
NumberAnimation {
targets: [animatedImagePreview, imagePreview]
property: "opacity"
duration: 200
}
NumberAnimation {
targets: [animatedImagePreview, imagePreview]
property: "anchors.topMargin"
duration: 100
}
}
}
},
Transition {
to: "scene"
SequentialAnimation {
ParallelAnimation {
NumberAnimation {
targets: [animatedImagePreview, imagePreview]
property: "opacity"
duration: 200
}
NumberAnimation {
targets: [animatedImagePreview, imagePreview]
property: "anchors.topMargin"
duration: 100
}
}
}
}
]
} }
states: [
State {
name: "inactive"
PropertyChanges {
target: root
anchors.rightMargin: -root.width
}
PropertyChanges {
target: imagePreview
opacity: 0
anchors.topMargin: 20
}
PropertyChanges {
target: animatedImagePreview
opacity: 0
anchors.topMargin: 20
}
},
State {
name: "activeWidget"
PropertyChanges {
target: sliderVolume
visible: false
}
PropertyChanges {
target: monitorSelection
visible: false
enabled: false
}
PropertyChanges {
target: imagePreview
opacity: 1
anchors.topMargin: 0
}
PropertyChanges {
target: animatedImagePreview
opacity: 1
anchors.topMargin: 0
}
PropertyChanges {
target: txtHeadlineMonitor
opacity: 0
}
},
State {
name: "activeWallpaper"
PropertyChanges {
target: imagePreview
opacity: 1
anchors.topMargin: 0
}
PropertyChanges {
target: animatedImagePreview
opacity: 1
anchors.topMargin: 0
}
PropertyChanges {
target: txtHeadlineMonitor
opacity: 1
}
PropertyChanges {
target: txtComboBoxFillMode
opacity: 1
visible: true
}
PropertyChanges {
target: cbVideoFillMode
opacity: 1
visible: true
}
},
State {
name: "activeScene"
PropertyChanges {
target: imagePreview
opacity: 1
anchors.topMargin: 0
}
PropertyChanges {
target: animatedImagePreview
opacity: 1
anchors.topMargin: 0
}
PropertyChanges {
target: txtHeadlineMonitor
opacity: 1
}
PropertyChanges {
target: sliderVolume
opacity: 0
visible: false
}
}
]
transitions: [
Transition {
to: "inactive"
from: "*"
reversible: true
NumberAnimation {
targets: [animatedImagePreview, imagePreview]
property: "opacity"
duration: 200
}
NumberAnimation {
targets: [animatedImagePreview, imagePreview]
property: "anchors.topMargin"
duration: 400
}
NumberAnimation {
target: root
properties: "anchors.rightMargin"
duration: 250
easing.type: Easing.OutQuart
}
},
Transition {
to: "activeWidget"
from: "*"
SequentialAnimation {
NumberAnimation {
target: root
properties: "anchors.rightMargin"
duration: 250
easing.type: Easing.OutQuart
}
ParallelAnimation {
NumberAnimation {
targets: [animatedImagePreview, imagePreview]
property: "opacity"
duration: 200
}
NumberAnimation {
targets: [animatedImagePreview, imagePreview]
property: "anchors.topMargin"
duration: 100
}
}
}
},
Transition {
to: "activeWallpaper"
from: "*"
SequentialAnimation {
NumberAnimation {
target: root
properties: "anchors.rightMargin"
duration: 250
easing.type: Easing.OutQuart
}
ParallelAnimation {
NumberAnimation {
targets: [animatedImagePreview, imagePreview]
property: "opacity"
duration: 200
}
NumberAnimation {
targets: [animatedImagePreview, imagePreview]
property: "anchors.topMargin"
duration: 100
}
}
}
},
Transition {
to: "activeScene"
SequentialAnimation {
NumberAnimation {
target: root
properties: "anchors.rightMargin"
duration: 250
easing.type: Easing.OutQuart
}
ParallelAnimation {
NumberAnimation {
targets: [animatedImagePreview, imagePreview]
property: "opacity"
duration: 200
}
NumberAnimation {
targets: [animatedImagePreview, imagePreview]
property: "anchors.topMargin"
duration: 100
}
}
}
}
]
} }

View File

@ -40,7 +40,7 @@ Item {
"modalSource": content "modalSource": content
}); });
nav.setNavigation(name); nav.setNavigation(name);
sidebar.state = "inactive"; sidebar.close()
} }
Navigation.ExitPopup { Navigation.ExitPopup {
@ -147,9 +147,9 @@ Item {
Connections { Connections {
function onSetSidebarActive(active) { function onSetSidebarActive(active) {
if (active) if (active)
sidebar.state = "active"; sidebar.open()
else else
sidebar.state = "inactive"; sidebar.close()
} }
function onSetNavigationItem(pos) { function onSetNavigationItem(pos) {
@ -166,13 +166,7 @@ Item {
Installed.Sidebar { Installed.Sidebar {
id: sidebar id: sidebar
objectName: "installedSidebar" objectName: "installedSidebar"
navHeight: nav.height width: content.width
anchors {
top: parent.top
right: parent.right
bottom: parent.bottom
}
} }
Navigation.Navigation { Navigation.Navigation {

View File

@ -69,6 +69,7 @@ Rectangle {
} }
function resize() { function resize() {
print("resize")
var absoluteDesktopSize = App.monitorListModel.absoluteDesktopSize(); var absoluteDesktopSize = App.monitorListModel.absoluteDesktopSize();
var isWidthGreaterThanHeight = false; var isWidthGreaterThanHeight = false;
var windowsDelta = 0; var windowsDelta = 0;
@ -161,4 +162,23 @@ Rectangle {
snapMode: ScrollBar.SnapOnRelease snapMode: ScrollBar.SnapOnRelease
} }
} }
ToolButton {
onClicked: App.monitorListModel.reset()
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/font-awsome/rotate-right-solid.svg"
icon.width: 14
icon.height: 14
opacity: hovered ? 1 : .4
hoverEnabled: true
Behavior on opacity {
NumberAnimation {
duration: 250
}
}
anchors {
top: parent.top
right: parent.right
}
}
} }

View File

@ -22,7 +22,7 @@ GlobalVariables::GlobalVariables(QObject* parent)
} else { } else {
setVersion(GlobalVariables::Version::OpenSourceStandalone); setVersion(GlobalVariables::Version::OpenSourceStandalone);
} }
setVersion(GlobalVariables::Version::OpenSourceUltraSteam); setVersion(GlobalVariables::Version::OpenSourceStandalone);
setLocalSettingsPath(QUrl { QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) }); setLocalSettingsPath(QUrl { QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation) });
} }

View File

@ -565,74 +565,22 @@ bool ScreenPlayManager::loadProfiles()
} }
} }
for (QJsonValueRef wallpaper : wallpaper.toObject().value("wallpaper").toArray()) { // for (QJsonValueRef wallpaper : wallpaper.toObject().value("wallpaper").toArray()) {
// QJsonObject wallpaperObj = wallpaper.toObject();
// if (!loadWallpaperConfig(wallpaperObj))
// containsInvalidData = true;
// }
for (QJsonValueRef timelineWallpaper : wallpaper.toObject().value("timelineWallpaper").toArray()) {
QJsonObject wallpaperObj = wallpaper.toObject(); QJsonObject wallpaperObj = wallpaper.toObject();
if (!loadTimelineWallpaperConfig(wallpaperObj))
if (wallpaperObj.empty())
continue;
QJsonArray monitorsArray = wallpaper.toObject().value("monitors").toArray();
QVector<int> monitors;
for (const QJsonValueRef monitorNumber : monitorsArray) {
int value = monitorNumber.toInt(-1);
if (value == -1) {
qWarning() << "Could not parse monitor number to display content at";
return false;
}
if (monitors.contains(value)) {
qWarning() << "The monitor: " << value << " is sharing the config multiple times. ";
return false;
}
monitors.append(value);
}
float volume = static_cast<float>(wallpaperObj.value("volume").toDouble(-1.0));
if (volume == -1.0F)
volume = 1.0f;
const QString absolutePath = wallpaperObj.value("absolutePath").toString();
const QString fillModeString = wallpaperObj.value("fillMode").toString();
const QString previewImage = wallpaperObj.value("previewImage").toString();
const float playbackRate = wallpaperObj.value("playbackRate").toDouble(1.0);
const QString file = wallpaperObj.value("file").toString();
const QString typeString = wallpaperObj.value("type").toString();
const QJsonObject properties = wallpaperObj.value("properties").toObject();
const auto type = QStringToEnum<ContentTypes::InstalledType>(typeString, ContentTypes::InstalledType::VideoWallpaper);
const auto fillMode = QStringToEnum<Video::FillMode>(fillModeString, Video::FillMode::Cover);
const bool success = createWallpaper(type, fillMode, absolutePath, previewImage, file, monitors, volume, playbackRate, properties, false);
if (!success) {
qWarning() << "Unable to start Wallpaper! " << type << fillMode << monitors << absolutePath;
containsInvalidData = true; containsInvalidData = true;
}
} }
for (const QJsonValueRef widget : wallpaper.toObject().value("widgets").toArray()) { for (const QJsonValueRef widget : wallpaper.toObject().value("widgets").toArray()) {
QJsonObject widgetObj = widget.toObject(); QJsonObject widgetObj = widget.toObject();
if (!loadWidgetConfig(widgetObj))
if (widgetObj.empty())
continue;
const QString absolutePath = widgetObj.value("absolutePath").toString();
const QString previewImage = widgetObj.value("previewImage").toString();
const QString typeString = widgetObj.value("type").toString();
const int positionX = widgetObj.value("positionX").toInt(0);
const int positionY = widgetObj.value("positionY").toInt(0);
const QPoint position { positionX, positionY };
const auto type = QStringToEnum<ContentTypes::InstalledType>(typeString, ContentTypes::InstalledType::QMLWidget);
const QJsonObject properties = widgetObj.value("properties").toObject();
const bool success = createWidget(type, position, absolutePath, previewImage, properties, false);
if (!success) {
qWarning() << "Unable to start Widget! " << type << position << absolutePath;
containsInvalidData = true; containsInvalidData = true;
}
} }
} }
@ -644,6 +592,87 @@ bool ScreenPlayManager::loadProfiles()
return true; return true;
} }
bool ScreenPlayManager::loadTimelineWallpaperConfig(const QJsonObject& wallpaperObj)
{
const QString name = wallpaperObj.value("name").toString();
const QString timeFormat = "hh:mm::ss";
const QTime startTime = QTime::fromString(wallpaperObj.value("startTime").toString(), timeFormat);
const QTime endTime = QTime::fromString(wallpaperObj.value("endTime").toString(), timeFormat);
if (!loadWallpaperConfig(wallpaperObj))
return false;
return true;
}
bool ScreenPlayManager::loadWallpaperConfig(const QJsonObject& wallpaperObj)
{
if (wallpaperObj.empty())
return false;
QJsonArray monitorsArray = wallpaperObj.value("monitors").toArray();
QVector<int> monitors;
for (const QJsonValueRef monitorNumber : monitorsArray) {
int value = monitorNumber.toInt(-1);
if (value == -1) {
qWarning() << "Could not parse monitor number to display content at";
return false;
}
if (monitors.contains(value)) {
qWarning() << "The monitor: " << value << " is sharing the config multiple times. ";
return false;
}
monitors.append(value);
}
float volume = static_cast<float>(wallpaperObj.value("volume").toDouble(-1.0));
if (volume == -1.0F)
volume = 1.0f;
const QString absolutePath = wallpaperObj.value("absolutePath").toString();
const QString fillModeString = wallpaperObj.value("fillMode").toString();
const QString previewImage = wallpaperObj.value("previewImage").toString();
const float playbackRate = wallpaperObj.value("playbackRate").toDouble(1.0);
const QString file = wallpaperObj.value("file").toString();
const QString typeString = wallpaperObj.value("type").toString();
const QJsonObject properties = wallpaperObj.value("properties").toObject();
const auto type = QStringToEnum<ContentTypes::InstalledType>(typeString, ContentTypes::InstalledType::VideoWallpaper);
const auto fillMode = QStringToEnum<Video::FillMode>(fillModeString, Video::FillMode::Cover);
const bool success = createWallpaper(type, fillMode, absolutePath, previewImage, file, monitors, volume, playbackRate, properties, false);
if (!success) {
qWarning() << "Unable to start Wallpaper! " << type << fillMode << monitors << absolutePath;
return false;
}
return true;
}
bool ScreenPlayManager::loadWidgetConfig(const QJsonObject& widgetObj)
{
if (widgetObj.empty())
return false;
const QString absolutePath = widgetObj.value("absolutePath").toString();
const QString previewImage = widgetObj.value("previewImage").toString();
const QString typeString = widgetObj.value("type").toString();
const int positionX = widgetObj.value("positionX").toInt(0);
const int positionY = widgetObj.value("positionY").toInt(0);
const QPoint position { positionX, positionY };
const auto type = QStringToEnum<ContentTypes::InstalledType>(typeString, ContentTypes::InstalledType::QMLWidget);
const QJsonObject properties = widgetObj.value("properties").toObject();
const bool success = createWidget(type, position, absolutePath, previewImage, properties, false);
if (!success) {
qWarning() << "Unable to start Widget! " << type << position << absolutePath;
return false;
}
return true;
}
} }
#include "moc_screenplaymanager.cpp" #include "moc_screenplaymanager.cpp"

View File

@ -0,0 +1,68 @@
{
"profiles": [
{
"appdrawer": [],
"name": "default",
"wallpaper": [
{
"name": "default",
"absolutePath": "C:/Program Files (x86)/Steam/steamapps/workshop/content/672870/05012024134225",
"file": "2_15488489005711.mp4",
"fillMode": "Contain",
"isLooping": true,
"monitors": [
0
],
"playbackRate": 1,
"previewImage": "previewThumbnail.jpg",
"type": "VideoWallpaper",
"volume": 0.6299999952316284
}
],
"timelineWallpaper": [
{
"name": "test",
"startTime": "00:00:00",
"endTime": "12:00:00",
"wallpaper": [
{
"absolutePath": "C:/Program Files (x86)/Steam/steamapps/workshop/content/672870/05012024134225",
"file": "2_15488489005711.mp4",
"fillMode": "Contain",
"isLooping": true,
"monitors": [
0
],
"playbackRate": 1,
"previewImage": "previewThumbnail.jpg",
"type": "VideoWallpaper",
"volume": 0.6299999952316284
}
]
},
{
"name": "test",
"startTime": "12:01",
"endTime": "24:00",
"wallpaper": [
{
"absolutePath": "C:/Program Files (x86)/Steam/steamapps/workshop/content/672870/05012024134225",
"file": "2_15488489005711.mp4",
"fillMode": "Contain",
"isLooping": true,
"monitors": [
0
],
"playbackRate": 1,
"previewImage": "previewThumbnail.jpg",
"type": "VideoWallpaper",
"volume": 0.6299999952316284
}
]
}
],
"widgets": []
}
],
"version": "1.0.0"
}

View File

@ -16,6 +16,11 @@ Rectangle {
height: 50 height: 50
color: Material.theme === Material.Light ? "white" : Material.background color: Material.theme === Material.Light ? "white" : Material.background
// Block input to underlying installed item
MouseArea {
anchors.fill: parent
}
Item { Item {
id: wrapper id: wrapper

View File

@ -34,8 +34,8 @@ Item {
Rotation { Rotation {
id: rt id: rt
origin.x: width * 0.5 origin.x: screenPlayItem.width * 0.5
origin.y: height * 0.5 origin.y: screenPlayItem.height * 0.5
angle: 0 angle: 0
axis { axis {
@ -50,15 +50,15 @@ Item {
Scale { Scale {
id: sc id: sc
origin.x: width * 0.5 origin.x: screenPlayItem.width * 0.5
origin.y: height * 0.5 origin.y: screenPlayItem.height * 0.5
} }
] ]
Timer { Timer {
id: timerAnim id: timerAnim
interval: 40 * itemIndex * Math.random() interval: 40 * screenPlayItem.itemIndex * Math.random()
running: true running: true
repeat: false repeat: false
onTriggered: showAnim.start() onTriggered: showAnim.start()
@ -151,7 +151,7 @@ Item {
id: screenPlayItemImage id: screenPlayItemImage
anchors.fill: parent anchors.fill: parent
sourceImage: Qt.resolvedUrl(screenPlayItem.absoluteStoragePath + "/" + screenPreview) sourceImage: Qt.resolvedUrl(screenPlayItem.absoluteStoragePath + "/" + screenPlayItem.screenPreview)
} }
Image { Image {
@ -193,17 +193,17 @@ Item {
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton acceptedButtons: Qt.LeftButton | Qt.RightButton
onEntered: { onEntered: {
if (!hasMenuOpen) if (!screenPlayItem.hasMenuOpen)
screenPlayItem.state = "hover"; screenPlayItem.state = "hover";
} }
onExited: { onExited: {
if (!hasMenuOpen) if (!screenPlayItem.hasMenuOpen)
screenPlayItem.state = "visible"; screenPlayItem.state = "visible";
} }
onClicked: { onClicked: function(mouse) {
checkBox.toggle(); checkBox.toggle();
if (mouse.button === Qt.LeftButton) if (mouse.button === Qt.LeftButton)
itemClicked(screenId, type, checkBox.checkState === Qt.Checked); itemClicked(screenPlayItem.folderName, type, checkBox.checkState === Qt.Checked);
} }
} }
} }
@ -213,9 +213,9 @@ Item {
onCheckStateChanged: { onCheckStateChanged: {
if (checkState == Qt.Checked) if (checkState == Qt.Checked)
isSelected = true; screenPlayItem.isSelected = true;
else else
isSelected = false; screenPlayItem.isSelected = false;
} }
anchors { anchors {

View File

@ -179,6 +179,7 @@ Drawer {
Layout.fillWidth: true Layout.fillWidth: true
icon.source: "qrc:/qml/ScreenPlayWorkshop/assets/icons/icon_thumb_up.svg" icon.source: "qrc:/qml/ScreenPlayWorkshop/assets/icons/icon_thumb_up.svg"
icon.color: "transparent"
ToolTip.visible: hovered ToolTip.visible: hovered
ToolTip.text: qsTr("Click here if you like the content") ToolTip.text: qsTr("Click here if you like the content")
onClicked: { onClicked: {
@ -193,6 +194,7 @@ Drawer {
Layout.fillWidth: true Layout.fillWidth: true
icon.source: "qrc:/qml/ScreenPlayWorkshop/assets/icons/icon_thumb_down.svg" icon.source: "qrc:/qml/ScreenPlayWorkshop/assets/icons/icon_thumb_down.svg"
icon.color: "transparent"
ToolTip.visible: hovered ToolTip.visible: hovered
ToolTip.text: qsTr("Click here if you do not like the content") ToolTip.text: qsTr("Click here if you do not like the content")
onClicked: { onClicked: {
@ -322,6 +324,7 @@ Drawer {
font.pointSize: 10 font.pointSize: 10
icon.source: "qrc:/qml/ScreenPlayWorkshop/assets/icons/icon_open_in_new.svg" icon.source: "qrc:/qml/ScreenPlayWorkshop/assets/icons/icon_open_in_new.svg"
icon.color: "transparent"
height: 25 height: 25
text: qsTr("Open In Steam") text: qsTr("Open In Steam")
onClicked: Qt.openUrlExternally("steam://url/CommunityFilePage/" + root.publishedFileID) onClicked: Qt.openUrlExternally("steam://url/CommunityFilePage/" + root.publishedFileID)

View File

@ -168,6 +168,7 @@ Item {
ToolButton { ToolButton {
onClicked: Qt.openUrlExternally("steam://url/CommunityFilePage/" + banner.bannerPublishedFileID) onClicked: Qt.openUrlExternally("steam://url/CommunityFilePage/" + banner.bannerPublishedFileID)
icon.source: "qrc:/qml/ScreenPlayWorkshop/assets/icons/icon_open_in_new.svg" icon.source: "qrc:/qml/ScreenPlayWorkshop/assets/icons/icon_open_in_new.svg"
icon.color: "transparent"
} }
} }
} }
@ -339,6 +340,7 @@ Item {
ToolButton { ToolButton {
property bool hasContent: tiSearch.text.length > 0 property bool hasContent: tiSearch.text.length > 0
icon.source: hasContent ? "qrc:/qml/ScreenPlayWorkshop/assets/icons/icon_close.svg" : "qrc:/qml/ScreenPlayWorkshop/assets/icons/icon_search.svg" icon.source: hasContent ? "qrc:/qml/ScreenPlayWorkshop/assets/icons/icon_close.svg" : "qrc:/qml/ScreenPlayWorkshop/assets/icons/icon_search.svg"
icon.color: "transparent"
onClicked: { onClicked: {
if (hasContent) { if (hasContent) {
root.state = "searching"; root.state = "searching";

View File

@ -36,7 +36,7 @@ VCPKG_BASE_PACKAGES = [
] ]
PYTHON_EXECUTABLE = "python" if sys.platform == "win32" else "python3" PYTHON_EXECUTABLE = "python" if sys.platform == "win32" else "python3"
FFMPEG_VERSION = "6.1" FFMPEG_VERSION = "6.1"
GODOT_VERSION = "4.2" GODOT_VERSION = "4.2.1"
GODOT_RELEASE_TYPE = "stable" GODOT_RELEASE_TYPE = "stable"
GODOT_DOWNLOAD_SERVER = "https://github.com/godotengine/godot-builds/releases/download" GODOT_DOWNLOAD_SERVER = "https://github.com/godotengine/godot-builds/releases/download"
if sys.platform == "win32": if sys.platform == "win32":