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

Add basic refactoring for installed drawer and

now so called content settings
This commit is contained in:
Elias Steurer 2024-05-29 13:01:16 +02:00
parent 59ce122225
commit a71b3ea53e
22 changed files with 624 additions and 654 deletions

View File

@ -51,6 +51,7 @@ set(HEADER
set(QML
# cmake-format: sort
main.qml
qml/MainApp.qml
qml/Components/TrayIcon.qml
qml/Components/LineHandle.qml
qml/Components/LineIndicator.qml
@ -84,14 +85,12 @@ set(QML
qml/Installed/ScreenPlayItem.qml
qml/Installed/ScreenPlayItemImage.qml
qml/Installed/InstalledDrawer.qml
qml/MainApp.qml
qml/Monitors/DefaultVideoControls.qml
qml/Monitors/MonitorSelection.qml
qml/Monitors/MonitorSelectionItem.qml
qml/Monitors/MonitorsProjectSettingItem.qml
qml/Monitors/MonitorsView.qml
qml/Monitors/SaveNotification.qml
qml/Monitors/WallpaperTimeline.qml
qml/ContentSettings/DefaultVideoControls.qml
qml/ContentSettings/MonitorSelection.qml
qml/ContentSettings/MonitorSelectionItem.qml
qml/ContentSettings/MonitorsProjectSettingItem.qml
qml/ContentSettings/ContentSettingsView.qml
qml/ContentSettings/SaveNotification.qml
qml/Navigation/ExitPopup.qml
qml/Navigation/Navigation.qml
qml/Settings/SettingBool.qml

View File

@ -69,14 +69,10 @@ public:
Q_INVOKABLE QVariantMap initialStopPositions();
Q_INVOKABLE bool setWallpaperAtTimelineIndex(
const ScreenPlay::ContentTypes::InstalledType type,
const ScreenPlay::Video::FillMode fillMode,
const QString& absolutePath,
const QString& previewImage,
const QString& file,
const QVector<int>& monitorIndex,
const float volume,
const float playbackRate,
const QJsonObject& properties,
const int timelineIndex,
const QString& identifier,
const bool saveToProfilesConfigFile);
@ -95,7 +91,7 @@ public:
Q_INVOKABLE bool setWallpaperFillModeAtMonitorIndex(const int index, const int fillmode);
Q_INVOKABLE bool setAllWallpaperValue(const QString& key, const QString& value);
Q_INVOKABLE bool setWallpaperValue(const QString& appID, const QString& key, const QString& value);
QVersionNumber getProfilesVersion() const;
signals:
void activeWallpaperCounterChanged(int activeWallpaperCounter);
@ -113,56 +109,9 @@ private slots:
bool saveProfiles();
void checkActiveWallpaperTimeline();
void newConnection();
void setActiveWallpaperCounter(int activeWallpaperCounter);
void setActiveWidgetsCounter(int activeWidgetsCounter);
public slots:
void setActiveWallpaperCounter(int activeWallpaperCounter)
{
if (m_activeWallpaperCounter == activeWallpaperCounter)
return;
m_activeWallpaperCounter = activeWallpaperCounter;
emit activeWallpaperCounterChanged(m_activeWallpaperCounter);
}
void setActiveWidgetsCounter(int activeWidgetsCounter)
{
if (m_activeWidgetsCounter == activeWidgetsCounter)
return;
m_activeWidgetsCounter = activeWidgetsCounter;
emit activeWidgetsCounterChanged(m_activeWidgetsCounter);
}
void increaseActiveWidgetsCounter()
{
m_activeWidgetsCounter++;
emit activeWidgetsCounterChanged(m_activeWidgetsCounter);
}
void decreaseActiveWidgetsCounter()
{
if (m_activeWidgetsCounter <= 0) {
return;
}
m_activeWidgetsCounter--;
emit activeWidgetsCounterChanged(m_activeWidgetsCounter);
}
void increaseActiveWallpaperCounter()
{
m_activeWallpaperCounter++;
emit activeWallpaperCounterChanged(m_activeWallpaperCounter);
}
void decreaseActiveWallpaperCounter()
{
if (m_activeWallpaperCounter <= 0) {
return;
}
m_activeWallpaperCounter--;
emit activeWallpaperCounterChanged(m_activeWallpaperCounter);
}
private:
void printTimelines();
@ -195,6 +144,8 @@ private:
QTimer m_saveLimiter;
QTimer m_contentTimer;
Util m_util;
// We use a 24 hour system
const QString m_timelineTimeFormat = "hh:mm:ss";
const quint16 m_webSocketPort = 16395;

View File

@ -60,6 +60,10 @@ class ScreenPlayWallpaper;
// WallpaperTimeline. Only the active timeline section has
// a filled vector of ScreenPlayWallpaper
struct WallpaperTimelineSection {
// Is active is needed as an additional flag during switching.
// When timeline A is no longer in the time range, then we can
// use this flag to know that it was the last active timeline and
// remove all active wallpaper.
bool isActive = false;
QString identifier;

View File

@ -28,7 +28,6 @@ int main(int argc, char* argv[])
#if !defined(Q_OS_LINUX)
qputenv("QT_MEDIA_BACKEND", "ffmpeg");
#endif
QGuiApplication qtGuiApp(argc, argv);
ScreenPlay::ApplicationEngine appEngine;

View File

@ -13,7 +13,8 @@ Control {
leftPadding: 20
rightPadding: 20
property int activeTimelineIndex: 0
property int activeTimelineIndex: -1
property int length: timeLine.sectionsList.length
function getActiveTimeline() {
return timeLine.sectionsList[root.activeTimelineIndex];

View File

@ -56,6 +56,7 @@ SystemTrayIcon {
MenuItem {
text: qsTr("Browse Workshop")
enabled: App.globalVariables.isSteamVersion()
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_steam.svg"
onTriggered: {
root.open();

View File

@ -6,6 +6,7 @@ import QtQuick.Layouts
import QtQuick.Controls.Material.impl
import ScreenPlayApp
import ScreenPlayUtil as Util
import "../Components"
Util.Popup {

View File

@ -7,104 +7,112 @@ import QtQuick.Controls.Material
import QtQuick.Controls.Material.impl
import ScreenPlayApp
import ScreenPlayUtil
import "../Monitors"
import "../ContentSettings"
import "../Components"
Drawer {
id: root
height: 500
height: 250
modal: false
edge: Qt.BottomEdge
background: Rectangle {
color: Material.color(Material.Grey, Material.Shade900)
}
property bool hasPreviewGif: false
property var type: ContentTypes.InstalledType.QMLWallpaper
property string contentFolderName
onClosed: {
root.contentFolderName = "";
root.type = ContentTypes.InstalledType.Unknown;
root.contentFolderName = ""
root.type = ContentTypes.InstalledType.Unknown
}
function setInstalledDrawerItem(folderName, type) {
// Toggle sidebar if clicked on the same content twice
if (root.contentFolderName === folderName)
return;
root.contentFolderName = folderName;
root.type = type;
if (App.util.isWallpaper(root.type)) {
if (type === ContentTypes.InstalledType.VideoWallpaper)
installedDrawerWrapper.state = "wallpaper";
else
installedDrawerWrapper.state = "scene";
btnLaunchContent.text = qsTr("Set Wallpaper");
} else {
installedDrawerWrapper.state = "widget";
btnLaunchContent.text = qsTr("Set Widget");
return
if (!App.util.isWallpaper(root.type)){
return
}
root.open();
root.contentFolderName = folderName
root.type = type
if (type === ContentTypes.InstalledType.VideoWallpaper)
installedDrawerWrapper.state = "wallpaper"
else
installedDrawerWrapper.state = "scene"
btnLaunchContent.text = qsTr("Set Wallpaper")
root.open()
}
function indexOfValue(model, value) {
for (var i = 0; i < model.length; i++) {
let ourValue = model[i].value;
let ourValue = model[i].value
if (value === ourValue)
return i;
return i
}
return -1;
return -1
}
// 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();
imagePreview.source = "";
animatedImagePreview.source = "";
txtHeadline.text = "";
installedDrawerWrapper.state = "inactive";
root.close()
imagePreview.source = ""
animatedImagePreview.source = ""
txtHeadline.text = ""
installedDrawerWrapper.state = "inactive"
}
onContentFolderNameChanged: {
const item = App.installedListModel.get(root.contentFolderName);
const item = App.installedListModel.get(root.contentFolderName)
//txtHeadline.text = item.m_title
const previewGiFilePath = Qt.resolvedUrl(item.m_absoluteStoragePath + "/" + item.m_previewGIF);
const previewImageFilePath = Qt.resolvedUrl(item.m_absoluteStoragePath + "/" + item.m_preview);
root.hasPreviewGif = App.util.fileExists(previewGiFilePath);
const previewGiFilePath = Qt.resolvedUrl(
item.m_absoluteStoragePath + "/" + item.m_previewGIF)
const previewImageFilePath = Qt.resolvedUrl(
item.m_absoluteStoragePath + "/" + item.m_preview)
root.hasPreviewGif = App.util.fileExists(previewGiFilePath)
if (hasPreviewGif) {
animatedImagePreview.source = previewGiFilePath;
animatedImagePreview.playing = true;
animatedImagePreview.source = previewGiFilePath
animatedImagePreview.playing = true
} else {
imagePreview.source = previewImageFilePath;
imagePreview.source = previewImageFilePath
}
if (App.util.isWidget(root.type) || (monitorSelection.activeMonitors.length > 0)) {
btnLaunchContent.enabled = true;
return;
if (App.util.isWidget(root.type)
|| (monitorSelection.activeMonitors.length > 0)) {
btnLaunchContent.enabled = true
return
}
btnLaunchContent.enabled = false;
btnLaunchContent.enabled = false
}
RowLayout {
id: installedDrawerWrapper
state: "inactive"
spacing: 20
Item {
anchors.fill: parent
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.leftMargin: 10
spacing: 5
RowLayout {
id: installedDrawerWrapper
state: "inactive"
spacing: 30
anchors {
margins: 10
fill: parent
}
ColumnLayout {
spacing: 5
Layout.fillWidth: true
Layout.preferredHeight: 160
Layout.fillHeight: true
Layout.horizontalStretchFactor: 3
Text {
Layout.leftMargin: 20
text: qsTr("Select the duration your wallpaper should be visible")
text: qsTr("1. Select the duration your wallpaper should be visible")
font.family: App.settings.font
verticalAlignment: Text.AlignVCenter
font.pointSize: 11
font.pointSize: 14
color: Material.secondaryTextColor
}
@ -115,443 +123,364 @@ Drawer {
Connections {
target: App.screenPlayManager
function onPrintQmlTimeline() {
timeline.printTimelines();
timeline.printTimelines()
}
}
}
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
Layout.horizontalStretchFactor: 1
Button {
text: qsTr("Remove all timeline ranges")
ToolButton {
text: "❌" //qsTr("Remove all timeline ranges")
enabled: timeline.length > 1
onClicked: timeline.removeAll()
anchors {
right: parent.right
top: parent.top
}
}
}
}
ColumnLayout {
Layout.horizontalStretchFactor: 2
Layout.fillWidth: true
Layout.fillHeight: true
spacing: 10
Text {
text: qsTr("Select a Monitor to display the content")
text: qsTr("2. Select a Monitor to display the content")
font.family: App.settings.font
verticalAlignment: Text.AlignVCenter
font.pointSize: 11
font.pointSize: 14
color: Material.secondaryTextColor
}
MonitorSelection {
id: monitorSelection
objectName: "monitorSelection"
height: 200
height: 180
Layout.fillWidth: true
Layout.fillHeight: true
availableWidth: width
availableHeight: height
availableHeight: height - 20
fontSize: 11
}
}
}
ColumnLayout {
Layout.preferredWidth: 260
Layout.fillHeight: true
spacing: 10
Rectangle {
id: imageWrapper
color: "#2b2b2b"
Layout.preferredHeight: 180
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
// Do NOT enable async image loading!
// Otherwhise it will still hold the file
// when calling InstalledListModel::deinstallItemAt
// -> asynchronous: false
AnimatedImage {
id: animatedImagePreview
asynchronous: false
playing: true
fillMode: Image.PreserveAspectCrop
anchors.fill: parent
visible: enabled
enabled: root.hasPreviewGif
}
Image {
id: imagePreview
asynchronous: false
fillMode: Image.PreserveAspectCrop
anchors.fill: parent
enabled: !root.hasPreviewGif
visible: enabled
}
Rectangle {
id: tabShadow
height: 70
anchors {
bottom: parent.bottom
right: parent.right
left: parent.left
}
gradient: Gradient {
GradientStop {
position: 1
color: "#EE000000"
}
GradientStop {
position: 0
color: "#00000000"
}
}
}
Text {
id: txtHeadline
text: qsTr("Headline")
font.family: App.settings.font
verticalAlignment: Text.AlignBottom
font.pointSize: 16
color: "white"
wrapMode: Text.WordWrap
height: 50
anchors {
bottom: parent.bottom
right: parent.right
margins: 20
left: parent.left
}
}
}
ColumnLayout {
spacing: 20
Layout.horizontalStretchFactor: 1
Layout.fillHeight: true
Layout.fillWidth: true
Layout.alignment: Qt.AlignTop
spacing: 10
LabelSlider {
id: sliderVolume
Rectangle {
id: imageWrapper
color: "#2b2b2b"
Layout.preferredHeight: 100
Layout.fillWidth: true
headline: qsTr("Set Volume")
Layout.alignment: Qt.AlignTop
Layout.topMargin: 20
slider {
stepSize: 0.01
from: 0
value: 1
to: 1
// Do NOT enable async image loading!
// Otherwhise it will still hold the file
// when calling InstalledListModel::deinstallItemAt
// -> asynchronous: false
AnimatedImage {
id: animatedImagePreview
asynchronous: false
playing: true
fillMode: Image.PreserveAspectCrop
anchors.fill: parent
visible: enabled
enabled: root.hasPreviewGif
}
}
ColumnLayout {
Layout.fillWidth: true
spacing: 5
Image {
id: imagePreview
asynchronous: false
fillMode: Image.PreserveAspectCrop
anchors.fill: parent
enabled: !root.hasPreviewGif
visible: enabled
}
Rectangle {
id: tabShadow
height: 70
anchors {
bottom: parent.bottom
right: parent.right
left: parent.left
}
gradient: Gradient {
GradientStop {
position: 1
color: "#EE000000"
}
GradientStop {
position: 0
color: "#00000000"
}
}
}
Text {
id: txtComboBoxFillMode
id: txtHeadline
visible: false
text: qsTr("Fill Mode")
text: qsTr("Headline")
font.family: App.settings.font
verticalAlignment: Text.AlignVCenter
font.pointSize: 10
color: "#626262"
wrapMode: Text.WrapAnywhere
Layout.fillWidth: true
}
verticalAlignment: Text.AlignBottom
font.pointSize: 16
color: "white"
wrapMode: Text.WordWrap
height: 50
ComboBox {
id: cbVideoFillMode
visible: false
Layout.fillWidth: true
textRole: "text"
valueRole: "value"
font.family: App.settings.font
model: [
{
"value": Settings.FillMode.Stretch,
"text": qsTr("Stretch")
},
{
"value": Settings.FillMode.Fill,
"text": qsTr("Fill")
},
{
"value": Settings.FillMode.Contain,
"text": qsTr("Contain")
},
{
"value": Settings.FillMode.Cover,
"text": qsTr("Cover")
},
{
"value": Settings.FillMode.Scale_Down,
"text": qsTr("Scale-Down")
}
]
Component.onCompleted: {
cbVideoFillMode.currentIndex = root.indexOfValue(cbVideoFillMode.model, App.settings.videoFillMode);
anchors {
bottom: parent.bottom
right: parent.right
margins: 20
left: parent.left
}
}
}
}
Dialog {
id: dialog
standardButtons: Dialog.Ok
title: qsTr("Export Godot project")
property alias message: messageText.text
Text {
id: messageText
Dialog {
id: dialog
standardButtons: Dialog.Ok
title: qsTr("Export Godot project")
property alias message: messageText.text
Text {
id: messageText
}
}
}
Button {
id: btnLaunchContent
objectName: "btnLaunchContent"
enabled: App.util.isWidget(root.type) ? true : monitorSelection.isSelected
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_plus.svg"
icon.color: "white"
font.pointSize: 12
onClicked: {
const item = App.installedListModel.get(root.contentFolderName);
const absoluteStoragePath = item.m_absoluteStoragePath;
const previewImage = item.m_preview;
if (App.util.isWallpaper(root.type)) {
if (type === ContentTypes.InstalledType.GodotWallpaper) {
if (App.globalVariables.isBasicVersion()) {
installedDrawerWrapper.state = "inactive";
return;
}
}
let activeMonitors = monitorSelection.getActiveMonitors();
// TODO Alert user to choose a monitor
if (activeMonitors.length === 0)
return;
// We only have sliderVolume if it is a VideoWallpaper
let volume = 0;
if (type === ContentTypes.InstalledType.VideoWallpaper)
volume = Math.round(sliderVolume.slider.value * 100) / 100;
if (type === ContentTypes.InstalledType.GodotWallpaper) {
App.util.exportGodotProject(absoluteStoragePath, App.globalVariables.godotEditorExecutablePath).then(result => {
if (!result.success) {
dialog.title = ("Error exporting Godot");
dialog.message = result.message;
dialog.open();
} else {
const screenFile = item.m_file;
let success = App.screenPlayManager.createWallpaper(root.type, cbVideoFillMode.currentValue, absoluteStoragePath, previewImage, screenFile, activeMonitors, volume, 1, {}, true);
Button {
id: btnLaunchContent
Layout.fillWidth: true
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
objectName: "btnLaunchContent"
enabled: App.util.isWidget(root.type) && activeMonitors.length > 0 ? true : monitorSelection.isSelected
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_plus.svg"
icon.color: "white"
font.pointSize: 12
onClicked: {
const item = App.installedListModel.get(
root.contentFolderName)
const absoluteStoragePath = item.m_absoluteStoragePath
const previewImage = item.m_preview
if (App.util.isWallpaper(root.type)) {
if (type === ContentTypes.InstalledType.GodotWallpaper) {
if (App.globalVariables.isBasicVersion()) {
installedDrawerWrapper.state = "inactive"
return
}
});
root.close();
return;
}
let activeMonitors = monitorSelection.getActiveMonitors()
if (type === ContentTypes.InstalledType.GodotWallpaper) {
App.util.exportGodotProject(
absoluteStoragePath,
App.globalVariables.godotEditorExecutablePath).then(
result => {
if (!result.success) {
dialog.title = ("Error exporting Godot")
dialog.message = result.message
dialog.open()
} else {
const screenFile = item.m_file
let volume = 1
let success = App.screenPlayManager.createWallpaper(
root.type,
cbVideoFillMode.currentValue,
absoluteStoragePath,
previewImage,
screenFile,
activeMonitors,
volume,
1, {}, true)
}
})
root.close()
return
}
const activeTimeline = timeline.getActiveTimeline()
const file = item.m_file
let success = App.screenPlayManager.setWallpaperAtTimelineIndex(
root.type,
absoluteStoragePath,
previewImage,
file,
activeMonitors,
timeline.activeTimelineIndex,
activeTimeline.identifier, true)
}
const activeTimeline = timeline.getActiveTimeline();
const screenFile = item.m_file;
const playbackRate = 1;
const jsonProperties = {};
let success = App.screenPlayManager.setWallpaperAtTimelineIndex(
root.type, cbVideoFillMode.currentValue, absoluteStoragePath, previewImage, screenFile, activeMonitors, volume, playbackRate, jsonProperties, timeline.activeTimelineIndex, activeTimeline.identifier, true);
root.close()
monitorSelection.reset()
}
if (App.util.isWidget(root.type))
App.screenPlayManager.startWidget(type, Qt.point(0, 0), absoluteStoragePath, previewImage, {}, true);
root.close();
monitorSelection.reset();
}
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
}
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: monitorSelection
visible: false
enabled: false
}
PropertyChanges {
target: imagePreview
opacity: 1
anchors.topMargin: 0
}
PropertyChanges {
target: animatedImagePreview
opacity: 1
anchors.topMargin: 0
}
},
State {
name: "wallpaper"
PropertyChanges {
target: imagePreview
opacity: 1
anchors.topMargin: 0
}
PropertyChanges {
target: animatedImagePreview
opacity: 1
anchors.topMargin: 0
}
},
State {
name: "scene"
PropertyChanges {
target: imagePreview
opacity: 1
anchors.topMargin: 0
}
PropertyChanges {
target: animatedImagePreview
opacity: 1
anchors.topMargin: 0
}
}
]
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
}
}
}
}
]
}
ToolButton {
id: button
Layout.alignment: Qt.AlignTop
anchors {
top: parent.top
topMargin: -20
right: parent.right
}
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_close.svg"
icon.width: 15
icon.height: 15
onClicked: {
root.close();
installedDrawerWrapper.state = "inactive";
root.close()
installedDrawerWrapper.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
}
},
State {
name: "wallpaper"
PropertyChanges {
target: imagePreview
opacity: 1
anchors.topMargin: 0
}
PropertyChanges {
target: animatedImagePreview
opacity: 1
anchors.topMargin: 0
}
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: 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
}
}
}
}
]
}
}

View File

@ -223,7 +223,7 @@ Item {
type: m_type
isNew: m_isNew
containsAudio: m_containsAudio
screenId: m_folderName
folderName: m_folderName
absoluteStoragePath: m_absoluteStoragePath
publishedFileID: m_publishedFileID
itemIndex: index

View File

@ -4,12 +4,13 @@ import QtQuick.Controls
import QtQuick.Controls.Material
import ScreenPlayApp
import ScreenPlayUtil as Util
import QtQuick.Window
Item {
id: root
property string customTitle
property string screenId
property string folderName
property url absoluteStoragePath
property int type: Util.ContentTypes.InstalledType.Unknown
// Must be var to make it work wit 64bit ints
@ -20,13 +21,15 @@ Item {
property bool containsAudio: false
property int version: App.globalVariables.version
property bool hasLicense: {
if ((root.version === GlobalVariables.OpenSourceStandalone || root.version === GlobalVariables.OpenSourceSteam) && root.type === Util.ContentTypes.InstalledType.GodotWallpaper) {
return false;
if ((root.version === GlobalVariables.OpenSourceStandalone
|| root.version === GlobalVariables.OpenSourceSteam)
&& root.type === Util.ContentTypes.InstalledType.GodotWallpaper) {
return false
}
return true;
return true
}
signal clicked(var screenId, var type)
signal clicked(var folderName, var type)
signal openContextMenu(var point)
signal openOpenLicensePopup
@ -34,16 +37,16 @@ Item {
height: 180
onTypeChanged: {
if (App.util.isWidget(type)) {
icnType.source = "qrc:/qml/ScreenPlayApp/assets/icons/icon_widgets.svg";
return;
icnType.source = "qrc:/qml/ScreenPlayApp/assets/icons/icon_widgets.svg"
return
}
if (App.util.isScene(type)) {
icnType.source = "qrc:/qml/ScreenPlayApp/assets/icons/icon_code.svg";
return;
icnType.source = "qrc:/qml/ScreenPlayApp/assets/icons/icon_code.svg"
return
}
if (App.util.isVideo(type)) {
icnType.source = "qrc:/qml/ScreenPlayApp/assets/icons/icon_movie.svg";
return;
icnType.source = "qrc:/qml/ScreenPlayApp/assets/icons/icon_movie.svg"
return
}
}
@ -51,10 +54,10 @@ Item {
running: true
onTriggered: showAnim.start()
interval: {
var itemIndexMax = itemIndex;
var itemIndexMax = itemIndex
if (itemIndex > 30)
itemIndexMax = 3;
5 * itemIndexMax * Math.random();
itemIndexMax = 3
5 * itemIndexMax * Math.random()
}
}
@ -249,31 +252,74 @@ Item {
maskSource: mask
MouseArea {
id: hoverArea
anchors.fill: parent
hoverEnabled: !root.isScrolling && !showAnim.running
cursorShape: Qt.PointingHandCursor
acceptedButtons: Qt.LeftButton | Qt.RightButton
onEntered: {
if (!root.hasLicense)
return;
root.state = "hover";
screenPlayItemImage.state = "hover";
screenPlayItemImage.enter();
}
onExited: {
root.state = "";
screenPlayItemImage.state = "loaded";
screenPlayItemImage.exit();
}
onEntered: handleMouseEnter()
onExited: handleMouseExit()
onClicked: function (mouse) {
if (!root.hasLicense) {
root.openOpenLicensePopup();
return;
root.openOpenLicensePopup()
return
}
if (App.util.isWidget(root.type))
return
if (mouse.button === Qt.LeftButton)
root.clicked(root.screenId, root.type);
root.clicked(root.folderName, root.type)
else if (mouse.button === Qt.RightButton)
root.openContextMenu(Qt.point(mouseX, mouseY));
root.openContextMenu(Qt.point(mouseX, mouseY))
}
function handleMouseEnter(){
if (!root.hasLicense)
return
root.state = "hover"
screenPlayItemImage.state = "hover"
screenPlayItemImage.enter()
}
function handleMouseExit(){
if(widgetStartButton.enabled && widgetStartButton.hovered)
return
root.state = ""
screenPlayItemImage.state = "loaded"
screenPlayItemImage.exit()
}
}
Button {
id: widgetStartButton
enabled: App.util.isWidget(root.type)
hoverEnabled: enabled
text: qsTr("Start")
opacity: enabled && (widgetStartButton.hovered || hoverArea.containsMouse) ? 1 : 0
onClicked: {
App.screenPlayManager.startWidget(
root.type, Qt.point(0, 0),
root.absoluteStoragePath,
m_preview, {}, true)
}
onHoveredChanged: {
print(hovered)
if(hovered)
hoverArea.handleMouseEnter()
else
hoverArea.handleMouseExit()
}
anchors {
horizontalCenter: parent.horizontalCenter
bottom: parent.bottom
bottomMargin: 5
}
Behavior on opacity {
PropertyAnimation {
property: "opacity"
duration: 250
}
}
}
}
@ -322,11 +368,11 @@ Item {
to: 1
easing.type: Easing.OutQuart
}
},
Transition {
from: "hover"
to: ""
ScaleAnimator {
target: screenPlayItemWrapper
duration: 2000

View File

@ -2,7 +2,7 @@ import QtQuick
import QtQuick.Controls
import ScreenPlayUtil as Util
import ScreenPlayApp 1.0
import "Monitors" as Monitors
import "ContentSettings" as ContentSettings
import "Installed" as Installed
import "Navigation" as Navigation
import "Community" as Community
@ -58,8 +58,8 @@ Item {
modalSource: content
}
Monitors.MonitorsView {
id: monitors
ContentSettings.ContentSettingsView {
id: contentSettingsView
modalSource: content
}
TrayIcon {
@ -145,7 +145,9 @@ Item {
}
onChangePage: function (name) {
monitors.close();
// Close in case the user clicks
// on the tray icon
contentSettingsView.close();
switchPage(name);
}
}

View File

@ -1,81 +0,0 @@
import QtQuick
import QtQuick.Controls
Pane {
id: root
Component.onCompleted: {
// Add the second handle at 100% after the component is fully created
sliderHandles.append({
"position": sliderLine.width
});
}
ListModel {
id: sliderHandles
ListElement {
position: 0
} // Initial handle at 0%
}
Rectangle {
id: sliderLine
width: parent.width
height: 10
anchors.centerIn: parent
color: "grey"
MouseArea {
anchors.fill: parent
onClicked: {
var newHandlePosition = Math.max(0, Math.min(mouseX, sliderLine.width));
sliderHandles.append({
"position": newHandlePosition
});
// Sort handles after adding a new one
sortHandles();
}
}
}
Repeater {
model: sliderHandles
delegate: Rectangle {
id: handle
width: 10
height: 20
x: model.position - width / 2
y: sliderLine.y - height / 2 + sliderLine.height / 2
color: "blue"
MouseArea {
id: dragArea
anchors.fill: parent
drag.target: handle
drag.axis: Drag.XAxis
drag.minimumX: getMinimumX(index)
drag.maximumX: getMaximumX(index)
onReleased: {
sliderHandles.set(index, {
"position": handle.x + width / 2
});
}
}
}
}
function getMinimumX(index) {
return index > 0 ? sliderHandles.get(index - 1).position : 0;
}
function getMaximumX(index) {
return index < sliderHandles.count - 1 ? sliderHandles.get(index + 1).position - handle.width : sliderLine.width;
}
function sortHandles() {
sliderHandles.sort(function (a, b) {
return a.position - b.position;
});
}
}

View File

@ -295,16 +295,41 @@ Rectangle {
ToolTip.text: qsTr("Close All Content")
ToolTip.visible: hovered
}
ToolButton {
id: miConfig
Layout.alignment: Qt.AlignVCenter
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_video_settings.svg"
icon.width: root.iconWidth
icon.height: root.iconHeight
onClicked: App.util.setToggleWallpaperConfiguration()
hoverEnabled: true
ToolTip.text: qsTr("Configure Wallpaper")
ToolTip.visible: hovered
}
Button {
id: miConfig
icon.source: "qrc:/qml/ScreenPlayApp/assets/icons/icon_video_settings.svg"
icon.width: root.iconWidth
icon.height: root.iconHeight
onClicked: App.util.setToggleWallpaperConfiguration()
hoverEnabled: true
text: contentActive ? qsTr("Configure Content") : qsTr("No Active Content")
bottomInset: 10
topInset: 10
anchors {
top: parent.top
right: parent.right
rightMargin: 10
bottom: parent.bottom
}
Material.accent: contentActive ? "gold" : Material.secondaryTextColor
property bool contentActive: App.screenPlayManager.activeWallpaperCounter > 0
background: Rectangle {
color: Material.theme === Material.Light ? Material.background : "#242424"
border.color: {
if(contentActive){
return "gold"
} else {
Material.theme === Material.Light ? Material.iconDisabledColor : Qt.darker(
Material.background)
}
}
border.width: 1
radius: 3
}
}

View File

@ -61,6 +61,9 @@ std::shared_ptr<WallpaperTimelineSection> ScreenPlayManager::findActiveWallpaper
return nullptr;
}
/*!
\brief Returns the current active timline. There must always be an active timeline!
*/
std::shared_ptr<WallpaperTimelineSection> ScreenPlayManager::getCurrentTimeline()
{
const QTime currentTime = QTime::currentTime();
@ -69,6 +72,7 @@ std::shared_ptr<WallpaperTimelineSection> ScreenPlayManager::getCurrentTimeline(
return section;
}
}
qCritical() << "No active timeline";
return nullptr;
}
@ -109,6 +113,10 @@ void ScreenPlayManager::checkActiveWallpaperTimeline()
}
}
/*!
\brief Change active timeline. We need an extra flags to know if our
timeline is active and out of time range.
*/
void ScreenPlayManager::activateNewTimeline()
{
// Remove old timeline content
@ -150,29 +158,21 @@ void ScreenPlayManager::activateNewTimeline()
\brief Sets the wallpaper at a spesific timeline.
*/
bool ScreenPlayManager::setWallpaperAtTimelineIndex(
const ContentTypes::InstalledType type,
const Video::FillMode fillMode,
const ScreenPlay::ContentTypes::InstalledType type,
const QString& absolutePath,
const QString& previewImage,
const QString& file,
const QVector<int>& monitorIndex,
const float volume,
const float playbackRate,
const QJsonObject& properties,
const int timelineIndex,
const QString& identifier,
const bool saveToProfilesConfigFile)
{
WallpaperData wallpaperData;
wallpaperData.type = type;
wallpaperData.fillMode = fillMode;
wallpaperData.absolutePath = absolutePath;
wallpaperData.previewImage = previewImage;
wallpaperData.file = file;
wallpaperData.monitors = monitorIndex;
wallpaperData.volume = volume;
wallpaperData.playbackRate = playbackRate;
wallpaperData.properties = properties;
bool ok = false;
for (auto& timelineSection : m_wallpaperTimelineSectionsList) {
const bool sameIndex = timelineSection->index == timelineIndex;
@ -251,6 +251,7 @@ std::shared_ptr<ScreenPlayWallpaper> ScreenPlayManager::startWallpaper(
// Remove file:///
wallpaperData.absolutePath = QUrl::fromUserInput(wallpaperData.absolutePath).toLocalFile();
const QString appID = Util().generateRandomString();
qInfo() << "Start wallpaper" << wallpaperData.absolutePath << appID;
// Only support remove wallpaper that spans over 1 monitor
// if (wallpaperData.monitors.length() == 1) {
@ -281,7 +282,6 @@ std::shared_ptr<ScreenPlayWallpaper> ScreenPlayManager::startWallpaper(
return nullptr;
}
m_monitorListModel->setWallpaperMonitor(wallpaper, wallpaperData.monitors);
increaseActiveWallpaperCounter();
return wallpaper;
}
@ -326,7 +326,7 @@ bool ScreenPlayManager::startWidget(
if (!widget->start()) {
return false;
}
increaseActiveWidgetsCounter();
setActiveWidgetsCounter(activeWidgetsCounter() + 1);
m_screenPlayWidgets.append(widget);
return true;
}
@ -495,8 +495,10 @@ ScreenPlayWallpaper* ScreenPlayManager::getWallpaperByAppID(const QString& appID
return nullptr;
}
// We always handle the endTimeString, because it is the handle for the
// timeline. The last, default, timeline does not have a handle.
/*!
\brief We always handle the endTimeString, because it is the handle for the
timeline. The last, default, timeline does not have a handle.
*/
bool ScreenPlayManager::moveTimelineAt(const int index, const QString identifier, const float relativePosition, QString positionTimeString)
{
m_contentTimer.stop();
@ -528,6 +530,9 @@ bool ScreenPlayManager::moveTimelineAt(const int index, const QString identifier
return true;
}
/*!
\brief Converts a range from 0.0f - 1.0f to 00:00:00 0 23:59:59
*/
QString ScreenPlayManager::getTimeString(double relativeLinePosition)
{
if (relativeLinePosition == 1.0) {
@ -562,6 +567,9 @@ QString ScreenPlayManager::getTimeString(double relativeLinePosition)
return QString("%1:%2:%3").arg(hours, 2, 10, QChar('0')).arg(minutes, 2, 10, QChar('0')).arg(seconds, 2, 10, QChar('0'));
}
/*!
\brief Update m_wallpaperTimelineSectionsList index based on the startTime;
*/
void ScreenPlayManager::updateIndices()
{
// Sort the vector based on startTime
@ -576,6 +584,12 @@ void ScreenPlayManager::updateIndices()
}
}
/*!
\brief Adds a new timeline at relative position. We always shrink the timeline at the input
position and append the new one to the left. There must always (lightning) an active
timeline section.
*/
bool ScreenPlayManager::addTimelineAt(const int index, const float reltiaveLinePosition, QString identifier)
{
@ -632,7 +646,10 @@ bool ScreenPlayManager::addTimelineAt(const int index, const float reltiaveLineP
return true;
}
// Gets called from qml
/*!
\brief Qml function that removes all Timeline sections. Qml then creates
a new default section.
*/
void ScreenPlayManager::removeAllTimlineSections()
{
m_contentTimer.stop();
@ -665,6 +682,10 @@ void ScreenPlayManager::removeAllTimlineSections()
// the default timeline after this function
}
/*!
\brief Removes a timeline at a given index. Expands the timeline next to it
to fill the space.
*/
bool ScreenPlayManager::removeTimelineAt(const int index)
{
printTimelines();
@ -726,6 +747,9 @@ bool ScreenPlayManager::removeTimelineAt(const int index)
return true;
}
/*!
\brief Print to check if our qml data matches our c++.
*/
void ScreenPlayManager::printTimelines()
{
std::cout << "#############################\n";
@ -734,6 +758,9 @@ void ScreenPlayManager::printTimelines()
}
}
/*!
\brief Qml function to build our timeline on creation in qml.
*/
QVariantMap ScreenPlayManager::initialStopPositions()
{
QVariantMap sectionPositions;
@ -803,6 +830,24 @@ void ScreenPlayManager::newConnection()
m_unconnectedClients.push_back(std::move(connection));
}
void ScreenPlayManager::setActiveWallpaperCounter(int activeWallpaperCounter)
{
if (m_activeWallpaperCounter == activeWallpaperCounter)
return;
m_activeWallpaperCounter = activeWallpaperCounter;
emit activeWallpaperCounterChanged(m_activeWallpaperCounter);
}
void ScreenPlayManager::setActiveWidgetsCounter(int activeWidgetsCounter)
{
if (m_activeWidgetsCounter == activeWidgetsCounter)
return;
m_activeWidgetsCounter = activeWidgetsCounter;
emit activeWidgetsCounterChanged(m_activeWidgetsCounter);
}
/*!
\brief Removes a wallpaper from the given appID. Returns true on success.
*/
@ -814,10 +859,9 @@ bool ScreenPlayManager::removeWallpaper(const QString& appID)
qCritical() << "No timeline found.";
return false;
}
if (activeTimelineSection->activeWallpaperList.empty()) {
qCritical() << "No activeWallpaperList is empty for the current active timeline.";
return false;
}
if(activeTimelineSection->activeWallpaperList.empty())
return true;
activeTimelineSection->activeWallpaperList.erase(
std::remove_if(
@ -836,8 +880,6 @@ bool ScreenPlayManager::removeWallpaper(const QString& appID)
wallpaper->close();
decreaseActiveWallpaperCounter();
return true;
}));
@ -869,7 +911,8 @@ bool ScreenPlayManager::removeWidget(const QString& appID)
qInfo() << "Remove widget " << appID;
decreaseActiveWidgetsCounter();
setActiveWidgetsCounter(activeWidgetsCounter() - 1);
return true;
}),
@ -889,11 +932,18 @@ bool ScreenPlayManager::removeWidget(const QString& appID)
*/
bool ScreenPlayManager::setWallpaperValue(const QString& appID, const QString& key, const QString& value)
{
// for (auto& wallpaper : m_screenPlayWallpapers) {
// if (wallpaper->appID() == appID) {
// return wallpaper->setWallpaperValue(key, value, true);
// }
// }
std::shared_ptr<WallpaperTimelineSection> activeTimelineSection = findActiveWallpaperTimelineSection();
if(!activeTimelineSection){
qCritical() << "setWallpaperValue failed, because no active timeline section was found";
return false;
}
for (auto& wallpaper : activeTimelineSection->activeWallpaperList) {
if (wallpaper->appID() == appID) {
return wallpaper->setWallpaperValue(key, value, true);
}
}
qCritical() << "No wallpaper with matching appID was found";
return false;
}
@ -937,8 +987,8 @@ bool ScreenPlayManager::saveProfiles()
profile.insert("version", m_settings->getProfilesVersion().toString());
profile.insert("profiles", activeProfileList);
Util util;
if (util.writeJsonObjectToFile({ m_globalVariables->localSettingsPath().toString() + "/profiles.json" }, profile)) {
if (m_util.writeJsonObjectToFile({ m_globalVariables->localSettingsPath().toString() + "/profiles.json" }, profile)) {
emit profilesSaved();
return true;
}
@ -946,19 +996,20 @@ bool ScreenPlayManager::saveProfiles()
}
/*!
\brief Loads all wallpaper from profiles.json when the version number matches and starts the available wallpaper
\brief Loads all wallpaper from C:\Users\XXX\AppData\Local\ScreenPlay\ScreenPlay\profiles.json
when the version number matches and starts the available wallpaper
*/
bool ScreenPlayManager::loadProfiles()
{
Util util;
const auto configObj = util.openJsonFileToObject(m_globalVariables->localSettingsPath().toString() + "/profiles.json");
const auto configObj = m_util.openJsonFileToObject(m_globalVariables->localSettingsPath().toString() + "/profiles.json");
if (!configObj) {
qWarning() << "Could not load active profiles at path: " << m_globalVariables->localSettingsPath().toString() + "/profiles.json";
return false;
}
std::optional<QVersionNumber> version = util.getVersionNumberFromString(configObj->value("version").toString());
std::optional<QVersionNumber> version = m_util.getVersionNumberFromString(configObj->value("version").toString());
QVersionNumber requiredVersion = m_settings->getProfilesVersion();
if (version && *version != requiredVersion) {
qWarning() << "Version missmatch fileVersion: " << version->toString() << "m_version: " << requiredVersion.toString();
@ -989,7 +1040,7 @@ bool ScreenPlayManager::loadProfiles()
std::shared_ptr<WallpaperTimelineSection> wallpaperData = wallpaperDataOpt.value();
wallpaperData->index = m_wallpaperTimelineSectionsList.length();
wallpaperData->identifier = util.generateRandomString(4);
wallpaperData->identifier = m_util.generateRandomString(4);
qInfo() << wallpaperData->index
<< wallpaperData->startTime
@ -1016,6 +1067,7 @@ bool ScreenPlayManager::loadProfiles()
return true;
}
/*!
* \brief Calculates the relative position of a given time within a day.
*
@ -1044,6 +1096,18 @@ float calculateRelativePosition(const QTime& endTime)
return qRound(relativePosition * 10000.0) / 10000.0;
}
/*!
\brief Parses one timeline wallpaper:
"timelineWallpaper": [
{
"endTime": "08:32:00",
"startTime": "00:00:00",
"wallpaper": [
[...]
]
},
*/
std::optional<std::shared_ptr<WallpaperTimelineSection>> ScreenPlayManager::loadTimelineWallpaperConfig(const QJsonObject& timelineObj)
{
const QTime startTime = QTime::fromString(timelineObj.value("startTime").toString(), m_timelineTimeFormat);
@ -1068,6 +1132,32 @@ std::optional<std::shared_ptr<WallpaperTimelineSection>> ScreenPlayManager::load
return timelineSection;
}
/*!
\brief Loads the wallpaper object in the wallpaper array:
"timelineWallpaper": [
{
"endTime": "08:32:00",
"startTime": "00:00:00",
"wallpaper": [
{
"absolutePath": "file:///C:/Code/Cpp/ScreenPlay/672870/1234567",
"file": "AAA.webm",
"fillMode": "Cover",
"isLooping": false,
"monitors": [
0
],
"playbackRate": 1,
"previewImage": "previewThumbnail.jpg",
"properties": {
},
"type": "VideoWallpaper",
"volume": 1
}
]
},
*/
std::optional<WallpaperData> ScreenPlayManager::loadWallpaperConfig(const QJsonObject& wallpaperObj)
{
if (wallpaperObj.empty())
@ -1111,6 +1201,9 @@ std::optional<WallpaperData> ScreenPlayManager::loadWallpaperConfig(const QJsonO
return wallpaperData;
}
/*!
\brief Loads a widget from C:\Users\XXX\AppData\Local\ScreenPlay\ScreenPlay\profiles.json
*/
bool ScreenPlayManager::loadWidgetConfig(const QJsonObject& widgetObj)
{
if (widgetObj.empty())

View File

@ -9,7 +9,7 @@ Item {
property bool refresh: false
property bool enabled: true
signal setSidebaractiveItem(var screenId, var type)
signal setSidebaractiveItem(var folderName, var type)
signal setNavigationItem(var pos)
signal setSidebarActive(var active)

View File

@ -81,7 +81,7 @@ Item {
width: gridView.cellWidth - 30
customTitle: m_title
type: m_type
screenId: m_folderName
folderName: m_folderName
absoluteStoragePath: m_absoluteStoragePath
publishedFileID: m_publishedFileID
preview: m_preview

View File

@ -14,14 +14,14 @@ Item {
property bool isSelected: false
property string customTitle: "name here"
property string absoluteStoragePath: ""
property string screenId: ""
property string folderName: ""
property string preview: ""
property var type
property bool hasMenuOpen: false
property var publishedFileID: 0
property int itemIndex
signal itemClicked(var screenId, var type, var isActive)
signal itemClicked(var folderName, var type, var isActive)
height: 250
onTypeChanged: {
@ -140,7 +140,7 @@ Item {
isSelected = true;
else
isSelected = false;
itemClicked(screenId, type, isSelected);
root.itemClicked(folderName, type, isSelected);
}
anchors {