diff --git a/ScreenPlay/Resources.qrc b/ScreenPlay/Resources.qrc
index a10350c6..7a1d0def 100644
--- a/ScreenPlay/Resources.qrc
+++ b/ScreenPlay/Resources.qrc
@@ -100,5 +100,20 @@
legal/lgpl-2.1.txt
assets/icons/icon_delete.svg
assets/icons/app.ico
+ assets/icons/icon_supervisor_account.svg
+ assets/icons/icon_new_releases.svg
+ assets/icons/icon_report_problem.svg
+ assets/icons/icon_help_center.svg
+ assets/icons/icon_forum.svg
+ assets/icons/icon_thumb_up.svg
+ assets/icons/icon_thumb_down.svg
+ assets/icons/icon_cake.afdesign
+ assets/icons/icon_window.svg
+ assets/WorkshopPreview.html
+ assets/images/ava.png
+ assets/images/mask.svg
+ assets/images/mask_workshop.png
+ assets/images/Untitled.png
+ assets/images/window.svg
diff --git a/ScreenPlay/app.cpp b/ScreenPlay/app.cpp
index 956598b3..4ebee074 100644
--- a/ScreenPlay/app.cpp
+++ b/ScreenPlay/app.cpp
@@ -124,8 +124,6 @@ App::App()
// ScreenPlayManager first to check if another ScreenPlay Instace is running
m_screenPlayManager = std::make_unique();
m_isAnotherScreenPlayInstanceRunning = m_screenPlayManager->isAnotherScreenPlayInstanceRunning();
-
-
}
/*!
@@ -181,6 +179,10 @@ void App::init()
}
qmlRegisterSingletonInstance("ScreenPlay", 1, 0, "ScreenPlay", this);
+
+ if (!loadSteamPlugin())
+ qWarning() << "Steam plugin not provided!";
+
m_mainWindowEngine->load(QUrl(QStringLiteral("qrc:/main.qml")));
}
@@ -199,4 +201,25 @@ void App::exit()
QTimer::singleShot(150, []() { QApplication::instance()->quit(); });
}
}
+
+bool App::loadSteamPlugin()
+{
+#ifdef Q_OS_MACOS
+ const QString fileSuffix = ".dylib";
+#endif
+#ifdef Q_OS_WIN
+ const QString fileSuffix = ".dll";
+#else
+ const QString fileSuffix = ".so";
+#endif
+
+ m_workshopPlugin.setFileName(QApplication::applicationDirPath() + "/ScreenPlayWorkshop" + fileSuffix);
+
+ if (!m_workshopPlugin.load()) {
+ return false;
+ }
+
+ const ScreenPlayWorkshopPlugin* workshopPlugin = reinterpret_cast(m_workshopPlugin.instance());
+ return true;
+}
}
diff --git a/ScreenPlay/app.h b/ScreenPlay/app.h
index 9b613809..250ec334 100644
--- a/ScreenPlay/app.h
+++ b/ScreenPlay/app.h
@@ -63,6 +63,8 @@
#include "src/settings.h"
#include "src/util.h"
+class ScreenPlayWorkshopPlugin;
+
namespace ScreenPlay {
class App : public QObject {
@@ -131,7 +133,6 @@ public:
return m_installedListFilter.get();
}
-
QQmlApplicationEngine* mainWindowEngine() const
{
return m_mainWindowEngine.get();
@@ -238,7 +239,6 @@ public slots:
emit installedListFilterChanged(m_installedListFilter.get());
}
-
void setMainWindowEngine(QQmlApplicationEngine* mainWindowEngine)
{
if (m_mainWindowEngine.get() == mainWindowEngine)
@@ -249,6 +249,10 @@ public slots:
}
private:
+ bool loadSteamPlugin();
+
+private:
+ QPluginLoader m_workshopPlugin;
std::unique_ptr m_mainWindowEngine;
std::unique_ptr m_create;
diff --git a/ScreenPlay/assets/WorkshopPreview.html b/ScreenPlay/assets/WorkshopPreview.html
new file mode 100644
index 00000000..2cdda277
--- /dev/null
+++ b/ScreenPlay/assets/WorkshopPreview.html
@@ -0,0 +1,21 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ScreenPlay/assets/icons/icon_thumb_down.svg b/ScreenPlay/assets/icons/icon_thumb_down.svg
new file mode 100644
index 00000000..c673773b
--- /dev/null
+++ b/ScreenPlay/assets/icons/icon_thumb_down.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ScreenPlay/assets/icons/icon_thumb_up.svg b/ScreenPlay/assets/icons/icon_thumb_up.svg
new file mode 100644
index 00000000..8f3b5f05
--- /dev/null
+++ b/ScreenPlay/assets/icons/icon_thumb_up.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ScreenPlay/assets/images/Untitled.png b/ScreenPlay/assets/images/Untitled.png
new file mode 100644
index 00000000..e1a31bdd
Binary files /dev/null and b/ScreenPlay/assets/images/Untitled.png differ
diff --git a/ScreenPlay/assets/images/ava.png b/ScreenPlay/assets/images/ava.png
new file mode 100644
index 00000000..0cdbe59c
Binary files /dev/null and b/ScreenPlay/assets/images/ava.png differ
diff --git a/ScreenPlay/assets/images/mask.svg b/ScreenPlay/assets/images/mask.svg
new file mode 100644
index 00000000..1d490420
--- /dev/null
+++ b/ScreenPlay/assets/images/mask.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/ScreenPlay/assets/images/mask_workshop.png b/ScreenPlay/assets/images/mask_workshop.png
new file mode 100644
index 00000000..e1a31bdd
Binary files /dev/null and b/ScreenPlay/assets/images/mask_workshop.png differ
diff --git a/ScreenPlay/qml.qrc b/ScreenPlay/qml.qrc
index 2fc4fdc1..ad512dae 100644
--- a/ScreenPlay/qml.qrc
+++ b/ScreenPlay/qml.qrc
@@ -58,5 +58,20 @@
assets/icons/icon_report_problem.svg
assets/icons/icon_help_center.svg
assets/icons/icon_forum.svg
+ qml/Workshop/ScreenPlayItem.qml
+ qml/Workshop/ScreenPlayItemImage.qml
+ qml/Workshop/WorkshopAlertBanner.qml
+ qml/Workshop/WorkshopBackground.qml
+ qml/Workshop/WorkshopBanner.qml
+ qml/Workshop/WorkshopInstalled.qml
+ qml/Workshop/WorkshopItem.qml
+ qml/Workshop/WorkshopItemDetail.qml
+ qml/Workshop/WorkshopNavigation.qml
+ qml/Workshop/WorkshopPopupOffline.qml
+ qml/Workshop/WorkshopWrapper.qml
+ qml/Workshop/upload/PopupSteamWorkshopAgreement.qml
+ qml/Workshop/upload/UploadProject.qml
+ qml/Workshop/upload/UploadProjectBigItem.qml
+ qml/Workshop/upload/UploadProjectItem.qml
diff --git a/ScreenPlay/qml/Workshop/ScreenPlayItem.qml b/ScreenPlay/qml/Workshop/ScreenPlayItem.qml
new file mode 100644
index 00000000..7e76eb19
--- /dev/null
+++ b/ScreenPlay/qml/Workshop/ScreenPlayItem.qml
@@ -0,0 +1,288 @@
+import QtQuick 2.12
+import QtGraphicalEffects 1.0
+import QtQuick.Controls 2.3
+import QtQuick.Controls.Styles 1.4
+
+Item {
+ id: screenPlayItem
+ width: 320
+ height: 180
+ property alias checkBox: checkBox
+ state: "invisible"
+ opacity: 0
+
+ property string preview: screenPreview
+ property bool isSelected: false
+ property string customTitle: "name here"
+ property string absoluteStoragePath
+ property string type
+ property bool hasMenuOpen: false
+ property int workshopID: 0
+ property int itemIndex
+ property string screenId: ""
+ signal itemClicked(var screenId, var type, var isActive)
+
+ onTypeChanged: {
+ if (type === "widget") {
+ icnType.source = "icons/icon_widgets.svg"
+ } else if (type === "qmlScene") {
+ icnType.source = "icons/icon_code.svg"
+ }
+ }
+
+ Component.onCompleted: {
+ screenPlayItem.state = "visible"
+ }
+
+ Timer {
+ id: timerAnim
+ interval: 40 * itemIndex * Math.random()
+ running: true
+ repeat: false
+ onTriggered: showAnim.start()
+ }
+
+ transform: [
+ Rotation {
+ id: rt
+ origin.x: width * .5
+ origin.y: height * .5
+ axis {
+ x: -.5
+ y: 0
+ z: 0
+ }
+ angle: 0
+ },
+ Translate {
+ id: tr
+ },
+ Scale {
+ id: sc
+ origin.x: width * .5
+ origin.y: height * .5
+ }
+ ]
+ ParallelAnimation {
+ id: showAnim
+ running: false
+ RotationAnimation {
+ target: rt
+ from: 90
+ to: 0
+ duration: 500
+ easing.type: Easing.OutQuint
+ property: "angle"
+ }
+ PropertyAnimation {
+ target: screenPlayItem
+ from: 0
+ to: 1
+ duration: 500
+ easing.type: Easing.OutQuint
+ property: "opacity"
+ }
+ PropertyAnimation {
+ target: tr
+ from: 80
+ to: 0
+ duration: 500
+ easing.type: Easing.OutQuint
+ property: "y"
+ }
+ PropertyAnimation {
+ target: sc
+ from: .8
+ to: 1
+ duration: 500
+ easing.type: Easing.OutQuint
+ properties: "xScale,yScale"
+ }
+ }
+
+ RectangularGlow {
+ id: effect
+ anchors {
+ top: parent.top
+ topMargin: 3
+ }
+
+ height: parent.height
+ width: parent.width
+ cached: true
+ glowRadius: 3
+ spread: 0.2
+ color: "black"
+ opacity: 0.4
+ cornerRadius: 15
+ }
+
+ Item {
+ id: screenPlayItemWrapper
+ anchors.centerIn: parent
+ height: 180
+ width: 320
+
+ Image {
+ id: mask
+ source: "qrc:/assets/img/window.svg"
+ sourceSize: Qt.size(screenPlayItem.width, screenPlayItem.height)
+ visible: false
+ smooth: true
+ fillMode: Image.PreserveAspectFit
+ }
+
+ Item {
+ id: itemWrapper
+ anchors.fill: parent
+ visible: false
+
+ ScreenPlayItemImage {
+ id: screenPlayItemImage
+ anchors.fill: parent
+ sourceImage: Qt.resolvedUrl(
+ screenPlayItem.absoluteStoragePath + "/" + screenPreview)
+
+
+ }
+
+ Image {
+ id: icnType
+ width: 20
+ height: 20
+ opacity: 0
+ sourceSize: Qt.size(20, 20)
+ anchors {
+ top: parent.top
+ left: parent.left
+ margins: 10
+ }
+ }
+
+ Rectangle {
+ color: "#AAffffff"
+ height: 30
+ visible: false
+ anchors {
+ right: parent.right
+ left: parent.left
+ bottom: parent.bottom
+ }
+ }
+ }
+
+ OpacityMask {
+ anchors.fill: itemWrapper
+ source: itemWrapper
+ maskSource: mask
+
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ acceptedButtons: Qt.LeftButton | Qt.RightButton
+ onEntered: {
+ if (!hasMenuOpen) {
+ screenPlayItem.state = "hover"
+ }
+ }
+ onExited: {
+ if (!hasMenuOpen) {
+ screenPlayItem.state = "visible"
+ }
+ }
+
+ onClicked: {
+ checkBox.toggle()
+ if (mouse.button === Qt.LeftButton) {
+ itemClicked(screenId, type, checkBox.checkState === Qt.Checked)
+ }
+ }
+ }
+ }
+
+ CheckBox {
+ id: checkBox
+ onCheckStateChanged: {
+ if(checkState == Qt.Checked){
+ isSelected = true
+ } else {
+ isSelected = false
+ }
+ }
+
+ anchors {
+ top: parent.top
+ right: parent.right
+ margins: 10
+ }
+ }
+ }
+
+ states: [
+ State {
+ name: "invisible"
+
+ PropertyChanges {
+ target: screenPlayItemWrapper
+ y: -10
+ opacity: 0
+ }
+ PropertyChanges {
+ target: effect
+ opacity: 0
+ }
+ },
+ State {
+ name: "visible"
+ PropertyChanges {
+ target: effect
+ opacity: 0.4
+ }
+ PropertyChanges {
+ target: screenPlayItemWrapper
+ y: 0
+ opacity: 1
+ }
+ PropertyChanges {
+ target: screenPlayItem
+ width: 320
+ height: 180
+ }
+ PropertyChanges {
+ target: icnType
+ opacity: 0
+ }
+ },
+ State {
+ name: "selected"
+
+ PropertyChanges {
+ target: screenPlayItemWrapper
+ y: 0
+ opacity: 1
+ }
+ PropertyChanges {
+ target: icnType
+ opacity: .5
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ from: "invisible"
+ to: "visible"
+ },
+ Transition {
+ from: "visible"
+ to: "selected"
+ reversible: true
+
+ PropertyAnimation {
+ target: icnType
+ property: "opacity"
+ duration: 80
+ }
+ }
+ ]
+}
diff --git a/ScreenPlay/qml/Workshop/ScreenPlayItemImage.qml b/ScreenPlay/qml/Workshop/ScreenPlayItemImage.qml
new file mode 100644
index 00000000..b68e472e
--- /dev/null
+++ b/ScreenPlay/qml/Workshop/ScreenPlayItemImage.qml
@@ -0,0 +1,59 @@
+import QtQuick 2.12
+
+Item {
+ id: screenPlayItemImage
+ width: 320
+ height: 121
+ state: "loading"
+
+ property string sourceImage
+ property string sourceImageGIF
+
+ Image {
+ id: image
+ anchors.fill: parent
+ fillMode: Image.PreserveAspectCrop
+ source: screenPlayItemImage.sourceImage.trim()
+ onStatusChanged: {
+ if (image.status === Image.Ready) {
+ screenPlayItemImage.state = "loaded"
+ } else if (image.status === Image.Error) {
+ source = "images/missingPreview.png"
+ screenPlayItemImage.state = "loaded"
+ }
+ }
+ }
+
+ states: [
+ State {
+ name: "loading"
+
+ PropertyChanges {
+ target: image
+ opacity: 0
+ }
+ },
+ State {
+ name: "loaded"
+
+ PropertyChanges {
+ target: image
+ opacity: 1
+ }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: "loading"
+ to: "loaded"
+
+ NumberAnimation {
+ target: image
+ property: "opacity"
+ duration: 300
+ easing.type: Easing.InOutQuad
+ }
+ }
+ ]
+}
diff --git a/ScreenPlay/qml/Workshop/Workshop.qml b/ScreenPlay/qml/Workshop/Workshop.qml
index a2fc9cfd..35ee30e1 100644
--- a/ScreenPlay/qml/Workshop/Workshop.qml
+++ b/ScreenPlay/qml/Workshop/Workshop.qml
@@ -2,7 +2,6 @@ import QtQuick 2.12
import QtQuick.Controls 2.3
import QtQuick.Controls.Material 2.2
import QtGraphicalEffects 1.0
-import ScreenPlay.Workshop 1.0
Item {
id: workshop
@@ -12,5 +11,4 @@ Item {
anchors.fill: parent
}
-
}
diff --git a/ScreenPlay/qml/Workshop/WorkshopAlertBanner.qml b/ScreenPlay/qml/Workshop/WorkshopAlertBanner.qml
new file mode 100644
index 00000000..4e01a83f
--- /dev/null
+++ b/ScreenPlay/qml/Workshop/WorkshopAlertBanner.qml
@@ -0,0 +1,114 @@
+import QtQuick 2.12
+import QtGraphicalEffects 1.0
+
+Item {
+ id: workshopAltertBannerWrapper
+ height: 50
+ state: "out"
+
+ anchors {
+ bottom: parent.bottom
+ right: parent.right
+ left: parent.left
+ }
+
+ Rectangle {
+ id: workshopAltertBanner
+ height: 50
+ color: "#3498db"
+ anchors {
+ top: parent.top
+ right: parent.right
+ left: parent.left
+ }
+ Image {
+ id: icoFrown
+ source: "qrc:/assets/icons/font-awsome/frown-o.svg"
+ sourceSize: Qt.size(18, 18)
+ anchors {
+ left: parent.left
+ leftMargin: 20
+ verticalCenter: parent.verticalCenter
+ }
+ }
+ Text {
+ id: name
+ text: qsTr("Oh No! Looks like there a only a few wallpapers and widgets! Help us by creating your own wallpapers and Widgets :)")
+ color: "white"
+ font.pointSize: 11
+
+ font.family: ScreenPlay.settings.font
+ anchors {
+ left: icoFrown.right
+ leftMargin: 20
+ verticalCenter: parent.verticalCenter
+ }
+ }
+ MouseArea {
+ anchors {
+ top: parent.top
+ right: closeWrapper.left
+ bottom: parent.bottom
+ left: parent.left
+ }
+ cursorShape: Qt.PointingHandCursor
+ onClicked: {
+ screenPlaySettings.setHasWorkshopBannerSeen(true)
+ ScreenPlay.ut.setNavigation("Create")
+ }
+ }
+
+ Item {
+ id: closeWrapper
+ height: 50
+ width: 50
+ anchors {
+ top: parent.top
+ right: parent.right
+ }
+ Image {
+ id: icoClose
+ source: "qrc:/assets/icons/font-awsome/close.svg"
+ sourceSize: Qt.size(15, 15)
+ anchors.centerIn: parent
+ }
+ MouseArea {
+ anchors.fill: parent
+ z: 99
+ onClicked: {
+ screenPlaySettings.setHasWorkshopBannerSeen(true)
+ workshopAltertBannerWrapper.state = "out"
+ }
+ }
+ }
+ }
+ states: [
+ State {
+ name: "out"
+ PropertyChanges {
+ target: workshopAltertBanner
+ anchors.bottomMargin: -50
+ }
+ },
+ State {
+ name: "in"
+ PropertyChanges {
+ target: workshopAltertBanner
+ anchors.bottomMargin: 0
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ from: "out"
+ to: "in"
+ reversible: true
+ NumberAnimation {
+ target: footer
+ property: "anchors.bottomMargin"
+ duration: 300
+ easing.type: Easing.InOutQuad
+ }
+ }
+ ]
+}
diff --git a/ScreenPlay/qml/Workshop/WorkshopBackground.qml b/ScreenPlay/qml/Workshop/WorkshopBackground.qml
new file mode 100644
index 00000000..4dc95632
--- /dev/null
+++ b/ScreenPlay/qml/Workshop/WorkshopBackground.qml
@@ -0,0 +1,162 @@
+import QtQuick 2.13
+import QtGraphicalEffects 1.0
+import ScreenPlay.Workshop 1.0
+
+Rectangle {
+ id: root
+ state: "base"
+ color: "#161C1D"
+ property string backgroundImage: ""
+ property int imageOffsetTop: 0
+ onImageOffsetTopChanged: {
+ if ((imageOffsetTop * -1) >= 300) {
+ root.state = "backgroundColor"
+ } else {
+ if (root.state !== "backgroundImage") {
+ root.state = "backgroundImage"
+ }
+ }
+ }
+ onBackgroundImageChanged: {
+ if (backgroundImage === "") {
+ root.state = "base"
+ } else {
+ root.state = "backgroundImage"
+ }
+ }
+
+ Image {
+ id: maskSource
+ visible: false
+ source: "qrc:/assets/images/mask_workshop.png"
+ }
+
+
+
+
+ Image {
+ id: bgImage
+ height: bgImage.sourceSize.height
+ anchors {
+ topMargin: root.imageOffsetTop
+ top: parent.top
+ right: parent.right
+ left: parent.left
+ }
+
+ fillMode: Image.PreserveAspectCrop
+ opacity: 0
+ source: root.backgroundImage
+
+ LinearGradient {
+ id: gradient
+ anchors.fill: parent
+ z: 4
+ gradient: Gradient {
+ GradientStop {
+ position: 0.0
+ color: "#00ffffff"
+ }
+ GradientStop {
+ position: .9
+ color: "#161C1D"
+ }
+ }
+ }
+ }
+
+ MaskedBlur {
+ id:blur
+ anchors.fill: bgImage
+ source: bgImage
+ maskSource: maskSource
+ radius: 16
+ cached: true
+ samples: 24
+ }
+
+
+
+ Rectangle {
+ id: bgColor
+ color: "#161C1D"
+ opacity: 0
+ anchors.fill: parent
+ }
+
+
+ states: [
+ State {
+ name: "base"
+ PropertyChanges {
+ target: bgImage
+ opacity: 0
+ }
+
+ PropertyChanges {
+ target: bgColor
+ opacity: 0
+ }
+ PropertyChanges {
+ target: blur
+ opacity: 0
+ }
+ },
+ State {
+ name: "backgroundImage"
+ PropertyChanges {
+ target: bgImage
+ opacity: 1
+ }
+
+ PropertyChanges {
+ target: bgColor
+ opacity: 0
+ }
+ PropertyChanges {
+ target: blur
+ opacity: 1
+ }
+ },
+ State {
+ name: "backgroundColor"
+ PropertyChanges {
+ target: bgImage
+ opacity: 0
+ }
+
+ PropertyChanges {
+ target: bgColor
+ opacity: 1
+ }
+ PropertyChanges {
+ target: blur
+ opacity: 1
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ from: "base"
+ to: "backgroundImage"
+ reversible: true
+ PropertyAnimation {
+ targets: [bgImage, bgColor, blur]
+ duration: 2000
+ easing.type: Easing.InOutQuart
+ property: "opacity"
+ }
+ },
+ Transition {
+ from: "backgroundImage"
+ to: "backgroundColor"
+ reversible: true
+ PropertyAnimation {
+ targets: [bgImage, bgColor]
+ duration: 1000
+ easing.type: Easing.InOutQuart
+ property: "opacity"
+ }
+ }
+ ]
+}
diff --git a/ScreenPlay/qml/Workshop/WorkshopBanner.qml b/ScreenPlay/qml/Workshop/WorkshopBanner.qml
new file mode 100644
index 00000000..822d45f0
--- /dev/null
+++ b/ScreenPlay/qml/Workshop/WorkshopBanner.qml
@@ -0,0 +1,51 @@
+import QtQuick 2.12
+import QtQuick.Controls 2.3
+
+Item {
+ Connections {
+ target: steamWorkshop
+ function onWorkshopSearched() {
+ bannerTxt.text = workshopListModel.getBannerText()
+ bannerImg.source = workshopListModel.getBannerUrl()
+ }
+ }
+
+ Rectangle {
+ id: banner
+ color: "#44131313"
+ height: 350
+ anchors {
+ top: parent.top
+ right: parent.right
+ left: parent.left
+ }
+ Image {
+ id: bannerImg
+ anchors {
+ right: parent.right
+ left: parent.left
+ bottom: parent.bottom
+ }
+
+ asynchronous: true
+ fillMode: Image.PreserveAspectCrop
+ }
+
+ Text {
+ id: bannerTxt
+ text: "loading"
+ font.pointSize: 36
+ color: "white"
+ }
+ }
+
+ Item {
+ id: searchBar
+ height: 70
+ anchors {
+ top: banner.bottom
+ right: parent.right
+ left: parent.left
+ }
+ }
+}
diff --git a/ScreenPlay/qml/Workshop/WorkshopInstalled.qml b/ScreenPlay/qml/Workshop/WorkshopInstalled.qml
new file mode 100644
index 00000000..334df2cc
--- /dev/null
+++ b/ScreenPlay/qml/Workshop/WorkshopInstalled.qml
@@ -0,0 +1,49 @@
+import QtQuick 2.12
+import QtQuick.Controls 2.3
+import QtQuick.Controls.Styles 1.4
+import QtGraphicalEffects 1.0
+import ScreenPlay.Workshop 1.0 as SP
+
+Item {
+ id: pageInstalled
+ state: "out"
+ clip: true
+
+ signal setSidebaractiveItem(var screenId, var type)
+ signal setNavigationItem(var pos)
+ signal setSidebarActive(var active)
+
+ property bool refresh: false
+ property bool enabled: true
+
+ Component.onCompleted: {
+ pageInstalled.state = "in"
+ }
+
+ Connections {
+ target: loaderHelp.item
+ function onHelperButtonPressed(pos) {
+ setNavigationItem(pos)
+ }
+ }
+
+ Loader {
+ id: loaderHelp
+ asynchronous: true
+ active: false
+ z: 99
+ anchors.fill: parent
+ source: "qrc:/qml/Installed/InstalledUserHelper.qml"
+ }
+
+
+
+ states: []
+
+ transitions: [
+ Transition {
+ from: "out"
+ to: "in"
+ }
+ ]
+}
diff --git a/ScreenPlay/qml/Workshop/WorkshopItem.qml b/ScreenPlay/qml/Workshop/WorkshopItem.qml
new file mode 100644
index 00000000..63df73d9
--- /dev/null
+++ b/ScreenPlay/qml/Workshop/WorkshopItem.qml
@@ -0,0 +1,478 @@
+import QtQuick 2.12
+import QtGraphicalEffects 1.0
+import QtQuick.Controls 2.3
+import QtQuick.Controls.Material 2.2
+import Qt.labs.platform 1.0
+import ScreenPlay.Workshop 1.0 as SP
+
+import ScreenPlay 1.0
+
+Item {
+ id: root
+ width: 320
+ height: 180
+
+ property url imgUrl
+ property url additionalPreviewUrl
+ property string name
+ property int workshopID
+ property int itemIndex
+ property int subscriptionCount
+
+ property bool isDownloading: false
+
+ signal clicked(int workshopID, url imgUrl)
+
+ RectangularGlow {
+ id: effect
+ anchors {
+ top: parent.top
+ topMargin: 3
+ }
+
+ height: parent.height
+ width: parent.width
+ cached: true
+ glowRadius: 3
+ spread: 0.2
+ color: "black"
+ opacity: 0.4
+ cornerRadius: 15
+ }
+ Timer {
+ id: timerAnim
+ interval: 40 * itemIndex * Math.random()
+ running: true
+ repeat: false
+ onTriggered: showAnim.start()
+ }
+
+ transform: [
+ Rotation {
+ id: rt
+ origin.x: width * .5
+ origin.y: height * .5
+ axis {
+ x: -.5
+ y: 0
+ z: 0
+ }
+ angle: 0
+ },
+ Translate {
+ id: tr
+ },
+ Scale {
+ id: sc
+ origin.x: width * .5
+ origin.y: height * .5
+ }
+ ]
+ ParallelAnimation {
+ id: showAnim
+ running: false
+ RotationAnimation {
+ target: rt
+ from: 90
+ to: 0
+ duration: 500
+ easing.type: Easing.OutQuint
+ property: "angle"
+ }
+ PropertyAnimation {
+ target: root
+ from: 0
+ to: 1
+ duration: 500
+ easing.type: Easing.OutQuint
+ property: "opacity"
+ }
+ PropertyAnimation {
+ target: tr
+ from: 80
+ to: 0
+ duration: 500
+ easing.type: Easing.OutQuint
+ property: "y"
+ }
+ PropertyAnimation {
+ target: sc
+ from: .8
+ to: 1
+ duration: 500
+ easing.type: Easing.OutQuint
+ properties: "xScale,yScale"
+ }
+ }
+
+ Item {
+ id: screenPlay
+ anchors.centerIn: parent
+ height: 180
+ width: 320
+
+ Image {
+ id: mask
+ source: "qrc:/assets/images/Window.svg"
+ sourceSize: Qt.size(screenPlay.width, screenPlay.height)
+ visible: false
+ smooth: true
+ fillMode: Image.PreserveAspectFit
+ }
+
+ Item {
+ id: itemWrapper
+ visible: false
+ anchors {
+ fill: parent
+ margins: 5
+ }
+
+ ScreenPlayItemImage {
+ id: screenPlayItemImage
+ anchors.fill: parent
+ sourceImage: root.imgUrl
+ sourceImageGIF: root.additionalPreviewUrl
+ }
+
+ LinearGradient {
+ id: shadow
+ height: 80
+ opacity: 0
+ cached: true
+ anchors {
+ bottom: parent.bottom
+ right: parent.right
+ left: parent.left
+ }
+ start: Qt.point(0, 80)
+ end: Qt.point(0, 0)
+ gradient: Gradient {
+ GradientStop {
+ position: 0.0
+ color: "#CC000000"
+ }
+ GradientStop {
+ position: 1.0
+ color: "#00000000"
+ }
+ }
+ }
+ Text {
+ id: txtTitle
+ text: root.name
+
+ opacity: 0
+ height: 30
+ width: 180
+ verticalAlignment: Text.AlignVCenter
+ color: "white"
+ font.pointSize: 18
+ wrapMode: Text.WordWrap
+ font.family: ScreenPlay.settings.font
+ anchors {
+ bottom: parent.bottom
+ right: button.left
+ rightMargin: 10
+ left: parent.left
+ leftMargin: 20
+ bottomMargin: -50
+ }
+ }
+
+ Button {
+ id: button
+ text: qsTr("Download")
+ anchors {
+ right: parent.right
+ rightMargin: 20
+ bottom: parent.bottom
+ bottomMargin: -50
+ }
+ opacity: 0
+ Material.background: Material.Orange
+ Material.foreground: "white"
+ icon.source: "qrc:/assets/icons/icon_download.svg"
+ icon.width: 12
+ icon.height: 12
+ }
+
+ Item {
+ id: openInWorkshop
+ height: 20
+ width: 20
+ z: 99
+ opacity: 0
+ anchors {
+ margins: 10
+ top: parent.top
+ right: parent.right
+ }
+ Image {
+ source: "qrc:/assets/icons/icon_open_in_new.svg"
+ sourceSize: Qt.size(parent.width, parent.height)
+ fillMode: Image.PreserveAspectFit
+ }
+ }
+ }
+
+ OpacityMask {
+ anchors.fill: itemWrapper
+ source: itemWrapper
+ maskSource: mask
+
+ MouseArea {
+ anchors.fill: parent
+ hoverEnabled: true
+ cursorShape: Qt.PointingHandCursor
+ onContainsMouseChanged: {
+ if (!isDownloading) {
+ if (containsMouse) {
+ root.state = "hover"
+ } else {
+ root.state = ""
+ }
+ }
+ }
+ onClicked: {
+ root.clicked(root.workshopID, root.imgUrl)
+ }
+ }
+ MouseArea {
+ cursorShape: Qt.PointingHandCursor
+ height: 50
+ anchors {
+ right: parent.right
+ left: parent.left
+ bottom: parent.bottom
+ }
+
+ onClicked: {
+ isDownloading = true
+ root.state = "downloading"
+ SP.Workshop.steamWorkshop.subscribeItem(root.workshopID)
+ ScreenPlay.setTrackerSendEvent("subscribeItem",
+ root.workshopID)
+ }
+
+ Connections {
+ target: SP.Workshop.steamWorkshop
+ function onWorkshopItemInstalled(appID, publishedFile) {
+ if (appID === SP.Workshop.steamWorkshop.appID) {
+ root.state = "installed"
+ }
+ }
+ }
+ }
+
+ MouseArea {
+ height: 20
+ width: 20
+ cursorShape: Qt.PointingHandCursor
+ anchors {
+ margins: 10
+ top: parent.top
+ right: parent.right
+ }
+ onClicked: {
+ Qt.openUrlExternally(
+ "steam://url/CommunityFilePage/" + root.workshopID)
+ }
+ }
+ }
+ FastBlur {
+ id: effBlur
+ anchors.fill: itemWrapper
+ source: itemWrapper
+ radius: 0
+ }
+
+ Item {
+ id: itmDownloading
+ opacity: 0
+ anchors {
+ top: parent.top
+ topMargin: 50
+ right: parent.right
+ bottom: parent.bottom
+ left: parent.left
+ }
+
+ Text {
+ id: txtDownloading
+ text: qsTr("Successfully subscribed to Workshop Item!")
+ color: "white"
+ font.pointSize: 18
+ wrapMode: Text.WordWrap
+ font.family: ScreenPlay.settings.font
+ horizontalAlignment: Qt.AlignHCenter
+ anchors {
+ verticalCenter: parent.verticalCenter
+ right: parent.right
+ rightMargin: 20
+ left: parent.left
+ leftMargin: 20
+ }
+ }
+ }
+ }
+
+ states: [
+ State {
+ name: "hover"
+
+ PropertyChanges {
+ target: button
+ opacity: 1
+ anchors.bottomMargin: 10
+ }
+
+ PropertyChanges {
+ target: openInWorkshop
+ opacity: .75
+ }
+
+ PropertyChanges {
+ target: txtTitle
+ opacity: 1
+ anchors.bottomMargin: 20
+ }
+
+ PropertyChanges {
+ target: shadow
+ opacity: 1
+ }
+ PropertyChanges {
+ target: effBlur
+ radius: 0
+ }
+ },
+ State {
+ name: "downloading"
+
+ PropertyChanges {
+ target: button
+ opacity: 0
+ }
+ PropertyChanges {
+ target: openInWorkshop
+ opacity: 0
+ }
+
+ PropertyChanges {
+ target: txtTitle
+ opacity: 0
+ }
+
+ PropertyChanges {
+ target: shadow
+ opacity: 0
+ }
+
+ PropertyChanges {
+ target: effBlur
+ radius: 64
+ }
+
+ PropertyChanges {
+ target: itmDownloading
+ opacity: 1
+ anchors.topMargin: 0
+ }
+ },
+ State {
+ name: "installed"
+
+ PropertyChanges {
+ target: button
+ opacity: 0
+ }
+
+ PropertyChanges {
+ target: txtTitle
+ opacity: 0
+ }
+
+ PropertyChanges {
+ target: shadow
+ opacity: 0
+ }
+
+ PropertyChanges {
+ target: effBlur
+ radius: 64
+ }
+
+ PropertyChanges {
+ target: itmDownloading
+ opacity: 1
+ anchors.topMargin: 0
+ }
+ PropertyChanges {
+ target: txtDownloading
+ text: qsTr("Download complete!")
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ from: ""
+ to: "hover"
+ reversible: true
+
+ PropertyAnimation {
+ target: button
+ duration: 100
+ properties: "opacity, anchors.bottomMargin"
+ }
+ PropertyAnimation {
+ target: openInWorkshop
+ duration: 100
+ properties: "opacity"
+ }
+ PropertyAnimation {
+ target: txtTitle
+ duration: 100
+ properties: "opacity, anchors.bottomMargin"
+ }
+ PropertyAnimation {
+ target: shadow
+ duration: 100
+ properties: "opacity"
+ }
+ },
+ Transition {
+ from: "*"
+ to: "downloading"
+ reversible: true
+
+ PropertyAnimation {
+ target: button
+ duration: 100
+ properties: "opacity"
+ }
+ PropertyAnimation {
+ target: txtTitle
+ duration: 100
+ properties: "opacity"
+ }
+ PropertyAnimation {
+ target: shadow
+ duration: 100
+ properties: "opacity"
+ }
+ SequentialAnimation {
+ PropertyAnimation {
+ target: effBlur
+ duration: 500
+ properties: "radius"
+ }
+ PropertyAnimation {
+ target: txtTitle
+ duration: 200
+ properties: "opacity, anchors.topMargin"
+ }
+ }
+ }
+ ]
+}
diff --git a/ScreenPlay/qml/Workshop/WorkshopItemDetail.qml b/ScreenPlay/qml/Workshop/WorkshopItemDetail.qml
new file mode 100644
index 00000000..9fdd8b23
--- /dev/null
+++ b/ScreenPlay/qml/Workshop/WorkshopItemDetail.qml
@@ -0,0 +1,373 @@
+import QtQuick 2.12
+import QtGraphicalEffects 1.0
+import QtQuick.Controls 2.3
+import QtQuick.Layouts 1.11
+import QtWebEngine 1.8
+import QtQuick.Controls.Material 2.2
+import ScreenPlay.Workshop 1.0 as SP
+import ScreenPlay 1.0
+
+Drawer {
+ id: root
+ edge: Qt.RightEdge
+ height: parent.height - 60
+ dim: false
+ modal: false
+ width: 400
+ interactive: false
+ background: Rectangle {
+ color: Material.theme === Material.Light ? "white" : Qt.darker(
+ Material.background)
+ opacity: .95
+ }
+ enter: Transition {
+ SmoothedAnimation {
+ velocity: 10
+ easing.type: Easing.InOutQuart
+ }
+ }
+ exit: Transition {
+ SmoothedAnimation {
+ velocity: 10
+ easing.type: Easing.InOutQuart
+ }
+ }
+
+ Component.onCompleted: {
+ WebEngine.settings.localContentCanAccessFileUrls = true
+ WebEngine.settings.localContentCanAccessRemoteUrls = true
+ WebEngine.settings.allowRunningInsecureContent = true
+ WebEngine.settings.accelerated2dCanvasEnabled = true
+ WebEngine.settings.javascriptCanOpenWindows = false
+ WebEngine.settings.showScrollBars = false
+ WebEngine.settings.playbackRequiresUserGesture = false
+ WebEngine.settings.focusOnNavigationEnabled = true
+ }
+
+ property url videoPreview
+ property alias imgUrl: img.source
+ property string name
+ property int workshopID
+ property int itemIndex
+ property int subscriptionCount
+ property bool subscribed: false
+
+ function setWorkshopItem(id, imgUrl, videoPreview, subscriptionCount) {
+
+ if (root.workshopID === id) {
+ if (!root.visible) {
+ root.open()
+ } else {
+ root.close()
+ }
+ return
+ }
+ webView.opacity = 0
+ root.workshopID = id
+ root.imgUrl = imgUrl
+ root.subscriptionCount = subscriptionCount
+ root.videoPreview = videoPreview
+ root.subscribed = false
+ txtVotesUp.highlighted = false
+ txtVotesDown.highlighted = false
+
+ if (!root.visible) {
+ root.open()
+ }
+ SP.Workshop.steamWorkshop.requestWorkshopItemDetails(workshopID)
+
+ webView.setVideo()
+ }
+
+ Connections {
+ target: SP.Workshop.steamWorkshop
+ function onRequestItemDetailReturned(title, tags, steamIDOwner, description, votesUp, votesDown, url, fileSize, publishedFileId) {
+
+ txtTitle.text = title
+ txtTags.tags = tags
+ const size = Math.floor((1000 * ((fileSize / 1024) / 1000)) / 1000)
+ txtFileSize.text = qsTr("Project size: ") + size + qsTr(" MB")
+ pbVotes.to = votesDown + votesUp
+ pbVotes.value = votesUp
+ txtVotesDown.text = votesDown
+ txtVotesUp.text = votesUp
+ if (description === "") {
+ description = qsTr("No description...")
+ }
+
+ txtDescription.text = description
+ pbVotes.hoverText = votesUp + " / " + votesDown
+ }
+ }
+
+ Item {
+ id: imgWrapper
+ width: parent.width
+ height: 220
+ Image {
+ id: img
+ fillMode: Image.PreserveAspectCrop
+ anchors.fill: parent
+ }
+ WebEngineView {
+ id: webView
+ anchors.fill: parent
+
+ opacity: 0
+ property bool ready: false
+ url: Qt.resolvedUrl(".") + "WorkshopPreview.html"
+ onUrlChanged: print(url)
+
+ Behavior on opacity {
+ NumberAnimation {
+ duration: 200
+ }
+ }
+
+ function getUpdateVideoCommand() {
+ let src = ""
+ src += "var videoPlayer1 = document.getElementById('video');\n"
+ src += "videoPlayer1.src = '" + root.videoPreview + "';\n"
+ src += "videoPlayer1.play();\n"
+
+ return src
+ }
+
+ function setVideo() {
+ if (!root.videoPreview.toString().startsWith("https"))
+ return
+
+ webView.runJavaScript(getUpdateVideoCommand(),
+ function (result) {
+ webView.opacity = 1
+ })
+ }
+ }
+
+ LinearGradient {
+ height: 50
+ cached: true
+
+ anchors {
+ bottom: parent.bottom
+ right: parent.right
+ left: parent.left
+ }
+ start: Qt.point(0, 50)
+ end: Qt.point(0, 0)
+ gradient: Gradient {
+ GradientStop {
+ position: 0.0
+ color: "#EE000000"
+ }
+ GradientStop {
+ position: 1.0
+ color: "#00000000"
+ }
+ }
+ }
+
+ Text {
+ id: txtTitle
+ font.family: ScreenPlay.settings.font
+ font.weight: Font.Thin
+ verticalAlignment: Text.AlignBottom
+ font.pointSize: 16
+ color: "white"
+ wrapMode: Text.WordWrap
+ elide: Text.ElideRight
+ height: 50
+ anchors {
+ bottom: parent.bottom
+ right: parent.right
+ margins: 20
+ left: parent.left
+ }
+ }
+
+ MouseArea {
+ id: button
+ height: 50
+ width: 50
+ anchors.top: parent.top
+ anchors.left: parent.left
+ cursorShape: Qt.PointingHandCursor
+ onClicked: root.close()
+
+ Image {
+ id: imgBack
+ source: "qrc:/assets/icons/icon_arrow_right.svg"
+ sourceSize: Qt.size(15, 15)
+ fillMode: Image.PreserveAspectFit
+ anchors.centerIn: parent
+ }
+ }
+ }
+
+ ColumnLayout {
+ anchors {
+ top: imgWrapper.bottom
+ right: parent.right
+ left: parent.left
+
+ margins: 20
+ }
+
+ spacing: 20
+
+ ColumnLayout {
+ Layout.fillHeight: true
+ Layout.fillWidth: true
+ spacing: 20
+
+ ColumnLayout {
+ Layout.maximumWidth: 280
+ Layout.alignment: Qt.AlignHCenter
+
+ RowLayout {
+ Layout.fillWidth: true
+ spacing: 20
+
+ ToolButton {
+ id: txtVotesUp
+ Layout.fillWidth: true
+ icon.source: "qrc:/assets/icons/icon_thumb_up.svg"
+ font.family: ScreenPlay.settings.font
+ ToolTip.visible: hovered
+ ToolTip.text: qsTr("Click here if you like the content")
+ onClicked: {
+ SP.Workshop.steamWorkshop.vote(root.workshopID,
+ true)
+ txtVotesUp.highlighted = true
+ txtVotesDown.highlighted = false
+ }
+ }
+ ToolButton {
+ id: txtVotesDown
+ Layout.fillWidth: true
+ icon.source: "qrc:/assets/icons/icon_thumb_down.svg"
+ font.family: ScreenPlay.settings.font
+ ToolTip.visible: hovered
+ ToolTip.text: qsTr("Click here if you do not like the content")
+ onClicked: {
+ SP.Workshop.steamWorkshop.vote(root.workshopID,
+ false)
+ txtVotesUp.highlighted = false
+ txtVotesDown.highlighted = true
+ }
+ }
+ }
+
+ ProgressBar {
+ id: pbVotes
+ property string hoverText
+ Layout.alignment: Qt.AlignHCenter
+ Layout.fillWidth: true
+ ToolTip.visible: hovered
+ ToolTip.text: hoverText
+ }
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+ spacing: 20
+
+ Text {
+ id: txtFileSize
+ color: Material.secondaryTextColor
+ font.family: ScreenPlay.settings.font
+ font.pointSize: 11
+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
+ }
+
+ Text {
+ id: txtTags
+ Layout.alignment: Qt.AlignLeft
+ text: qsTr("Tags: ") + tags
+ font.pointSize: 11
+ opacity: tags !== "" ? 1 : 0
+ Behavior on opacity {
+ NumberAnimation {
+ duration: 200
+ }
+ }
+
+ color: Material.secondaryTextColor
+ font.family: ScreenPlay.settings.font
+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
+ elide: Text.ElideRight
+ property string tags
+ }
+ }
+
+ RowLayout {
+ Layout.fillWidth: true
+ spacing: 20
+ Text {
+ id: txtSubscriptionCount
+ color: Material.secondaryTextColor
+ font.family: ScreenPlay.settings.font
+ font.pointSize: 11
+ text: qsTr("Subscribtions: ") + root.subscriptionCount
+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
+ }
+
+ ToolButton {
+ icon.source: "qrc:/assets/icons/icon_open_in_new.svg"
+ text: qsTr("Open In Steam")
+ //Material.color: Material.secondaryTextColor
+ onClicked: Qt.openUrlExternally(
+ "steam://url/CommunityFilePage/" + root.workshopID)
+ }
+ }
+
+ Rectangle {
+ Layout.fillWidth: true
+ Layout.minimumHeight: 150
+ Layout.fillHeight: true //txtDescription.paintedHeight > 100
+ color: Material.backgroundColor
+ radius: 3
+ ScrollView {
+ anchors.fill: parent
+ anchors.margins: 10
+ clip: true
+ ScrollBar.vertical.policy: ScrollBar.AsNeeded
+ ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
+
+ Text {
+ id: txtDescription
+ width: parent.width
+ color: Material.primaryTextColor
+ font.family: ScreenPlay.settings.font
+ font.pointSize: 10
+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
+ }
+ }
+ }
+ }
+ }
+
+ Button {
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ bottom: parent.bottom
+ bottomMargin: 20
+ }
+
+ highlighted: !root.subscribed
+ enabled: !root.subscribed
+ icon.source: "qrc:/assets/icons/icon_download.svg"
+ text: root.subscribed ? qsTr("Subscribed!") : qsTr("Subscribe")
+ onClicked: {
+ root.subscribed = true
+ SP.Workshop.steamWorkshop.subscribeItem(root.workshopID)
+ }
+ }
+}
+
+/*##^##
+Designer {
+ D{i:0;formeditorZoom:0.75;height:800;width:300}
+}
+##^##*/
+
diff --git a/ScreenPlay/qml/Workshop/WorkshopNavigation.qml b/ScreenPlay/qml/Workshop/WorkshopNavigation.qml
new file mode 100644
index 00000000..8f9672c6
--- /dev/null
+++ b/ScreenPlay/qml/Workshop/WorkshopNavigation.qml
@@ -0,0 +1,116 @@
+import QtQuick 2.13
+import QtQuick.Controls 2.13
+import QtQuick.Controls.Material 2.13
+import QtGraphicalEffects 1.0
+
+import ScreenPlay.Workshop 1.0
+import ScreenPlay.Workshop.SteamEnums 1.0
+import SteamQMLImageProvider 1.0
+import ScreenPlay 1.0
+
+Item {
+ id: root
+ width: 800
+ height: 60
+
+ signal uploadPressed
+
+ Rectangle {
+ id: bg
+ color: Material.theme === Material.Light ? "white" : Qt.darker(Material.background)
+ opacity: .9
+ radius: 3
+ anchors.fill: wrapper
+ }
+
+ Item {
+ id: wrapper
+
+ anchors {
+ top: parent.top
+ right: parent.right
+ left: parent.left
+ bottom: parent.bottom
+ bottomMargin: 5
+ }
+
+ Text {
+ id: name
+ text: {
+ return Workshop.steamWorkshop.steamAccount.username + qsTr(
+ " Subscribed items: ")
+ + Workshop.steamWorkshop.steamAccount.amountSubscribedItems
+ }
+
+ font.pointSize: 14
+ color: Material.primaryTextColor
+ font.family: ScreenPlay.settings.font
+ font.weight: Font.Thin
+ verticalAlignment: Qt.AlignVCenter
+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
+ anchors {
+ top: parent.top
+ left: avatar.right
+ leftMargin: 10
+ bottom: parent.bottom
+ right: btnUplaod.left
+ rightMargin: 10
+ }
+ }
+
+ SteamImage {
+ id: avatar
+ width: 40
+ height: 40
+ anchors {
+ left: parent.left
+ leftMargin: 10
+ verticalCenter: parent.verticalCenter
+ }
+ Component.onCompleted: Workshop.steamWorkshop.steamAccount.loadAvatar()
+ Connections {
+ target: Workshop.steamWorkshop.steamAccount
+ function onAvatarChanged(_avatar) {
+ avatar.setImage(_avatar)
+ }
+ }
+ }
+
+ Button {
+ id: btnUplaod
+ text: qsTr("Upload to the Steam Workshop")
+ Material.background: Material.accent
+ Material.foreground: "white"
+ icon.source: "qrc:/assets/icons/icon_plus.svg"
+ icon.color: "white"
+ icon.width: 16
+ icon.height: 16
+ highlighted: true
+
+ onClicked: uploadPressed()
+ anchors {
+ top: parent.top
+ right: parent.right
+ rightMargin: 10
+ bottom: parent.bottom
+ }
+ }
+ }
+
+ states: [
+ State {
+ name: "base"
+ PropertyChanges {
+ target: bg
+ radius: 3
+ }
+ },
+ State {
+ name: "scrolling"
+ PropertyChanges {
+ target: bg
+ radius: 0
+ }
+ }
+ ]
+}
diff --git a/ScreenPlay/qml/Workshop/WorkshopPopupOffline.qml b/ScreenPlay/qml/Workshop/WorkshopPopupOffline.qml
new file mode 100644
index 00000000..3014637a
--- /dev/null
+++ b/ScreenPlay/qml/Workshop/WorkshopPopupOffline.qml
@@ -0,0 +1,43 @@
+import QtQuick 2.0
+import QtQuick.Controls 2.13
+import QtQuick.Controls.Material 2.13
+import QtGraphicalEffects 1.0
+
+import ScreenPlay.Workshop 1.0
+import ScreenPlay 1.0
+
+Popup {
+ id: popupOffline
+ width: 1100
+ height: 600
+ modal: true
+ closePolicy: Popup.NoAutoClose
+ anchors.centerIn: Overlay.overlay
+ dim: true
+
+ background: Rectangle {
+ color: Material.theme === Material.Light ? "white" : Material.background
+ }
+
+ Text {
+ id: txtOffline
+ anchors.centerIn: parent
+ font.family: ScreenPlay.settings.font
+ font.pointSize: 21
+ color: Material.foreground
+ text: qsTr("You need to run Steam for this :)")
+ }
+
+ Button {
+ anchors {
+ horizontalCenter: parent.horizontalCenter
+ top: txtOffline.bottom
+ }
+ highlighted: true
+ text: qsTr("Back")
+ onClicked: {
+ ScreenPlay.util.setNavigation("Installed")
+ popupOffline.close()
+ }
+ }
+}
diff --git a/ScreenPlay/qml/Workshop/WorkshopWrapper.qml b/ScreenPlay/qml/Workshop/WorkshopWrapper.qml
new file mode 100644
index 00000000..f404f24a
--- /dev/null
+++ b/ScreenPlay/qml/Workshop/WorkshopWrapper.qml
@@ -0,0 +1,417 @@
+import QtQuick 2.13
+import QtQuick.Controls 2.13
+import QtQuick.Controls.Material 2.13
+import QtGraphicalEffects 1.0
+import QtQuick.Layouts 1.12
+
+import ScreenPlay.Workshop 1.0
+import ScreenPlay.Workshop.SteamEnums 1.0
+import ScreenPlay 1.0
+
+import "upload/"
+
+Item {
+ id: workshop
+ state: "base"
+ anchors.fill: parent
+ onVisibleChanged: {
+ if (!visible)
+ workshopItemDetail.close()
+ }
+
+ Component.onCompleted: {
+ if (Workshop.steamWorkshop.online) {
+ Workshop.steamWorkshop.workshopListModel.searchWorkshop(
+ SteamEnums.K_EUGCQuery_RankedByTrend)
+ } else {
+ popupOffline.open()
+ }
+ }
+
+ Connections {
+ target: Workshop.steamWorkshop.workshopListModel
+ function onWorkshopSearched() {
+ bannerTxt.text = Workshop.steamWorkshop.workshopListModel.getBannerText()
+ background.backgroundImage = Workshop.steamWorkshop.workshopListModel.getBannerUrl()
+ banner.bannerWorkshopID = Workshop.steamWorkshop.workshopListModel.getBannerID()
+ bannerTxtUnderline.numberSubscriber
+ = Workshop.steamWorkshop.workshopListModel.getBannerAmountSubscriber()
+ }
+ }
+
+ WorkshopBackground {
+ id: background
+ anchors.fill: parent
+ }
+
+ WorkshopPopupOffline {
+ id: popupOffline
+ }
+
+ UploadProject {
+ id: popupUploadProject
+ anchors.centerIn: Overlay.overlay
+ }
+
+ Flickable {
+ id: scrollView
+ anchors.fill: parent
+ contentWidth: parent.width
+ contentHeight: gridView.height + header.height + 300
+
+ onContentYChanged: {
+ // Calculate parallax scrolling
+ if (contentY >= 0) {
+ background.imageOffsetTop = (contentY * -.4)
+ } else {
+ background.imageOffsetTop = 0
+ }
+ if (contentY >= (header.height)) {
+ workshop.state = "scrolling"
+ } else {
+ workshop.state = "base"
+ }
+ }
+
+ transitions: Transition {
+ PropertyAnimation {
+ properties: "y"
+ easing.type: Easing.InOutQuad
+ duration: 300
+ }
+ }
+
+ // This wrapper is needed for the parent change
+ // of the nav. Otherwhise it wont work. Dunno why
+ Item {
+ id: wrapper
+ width: parent.width
+ height: nav.height + header.height + gridView.height
+
+ WorkshopNavigation {
+ id: nav
+ anchors.horizontalCenter: parent.horizontalCenter
+ onUploadPressed: popupUploadProject.open()
+ }
+
+ Item {
+ id: header
+ height: 440
+ anchors {
+ right: parent.right
+ left: parent.left
+ }
+
+ Item {
+ id: banner
+ height: 350
+ z: 5
+ property int bannerWorkshopID
+ anchors {
+ top: parent.top
+ right: parent.right
+ left: parent.left
+ }
+ Image {
+ id: bannerImg2
+ anchors {
+ right: parent.right
+ left: parent.left
+ bottom: parent.bottom
+ }
+ height: {
+
+ }
+
+ asynchronous: true
+ fillMode: Image.PreserveAspectCrop
+ }
+
+ ColumnLayout {
+ anchors {
+ top: parent.top
+ topMargin: 100
+ right: parent.right
+ left: parent.left
+ leftMargin: 100
+ }
+
+ Text {
+ id: bannerTxtUnderline
+ property int numberSubscriber: 0
+ text: numberSubscriber + " SUBSCRIBED TO:"
+ font.pointSize: 12
+ color: "white"
+ font.family: ScreenPlay.settings.font
+ font.weight: Font.Thin
+ }
+
+ Text {
+ id: bannerTxt
+ text: qsTr("Loading")
+ font.pointSize: 42
+ color: "white"
+ font.family: ScreenPlay.settings.font
+ font.weight: Font.Thin
+ width: 400
+ }
+
+ RowLayout {
+ spacing: 10
+ Button {
+ text: qsTr("Download now!")
+ Material.background: Material.accent
+ Material.foreground: "white"
+ icon.source: "qrc:/assets/icons/icon_download.svg"
+ onClicked: {
+ text = qsTr("Downloading...")
+ Workshop.steamWorkshop.subscribeItem(
+ Workshop.steamWorkshop.workshopListModel.getBannerID(
+ ))
+ }
+ }
+ Button {
+ text: qsTr("Details")
+ Material.background: Material.accent
+ Material.foreground: "white"
+ icon.source: "qrc:/assets/icons/icon_info.svg"
+ visible: false
+ onClicked: {
+ workshopItemDetail.setWorkshopItem(
+ workshopID, imgUrl,
+ additionalPreviewUrl,
+ subscriptionCount)
+ }
+ }
+ }
+
+ MouseArea {
+ onClicked: Qt.openUrlExternally(
+ "steam://url/CommunityFilePage/"
+ + banner.bannerWorkshopID)
+ height: 30
+ width: bannerTxtOpenInSteam.paintedWidth
+ cursorShape: Qt.PointingHandCursor
+ Text {
+ id: bannerTxtOpenInSteam
+ opacity: .7
+ text: qsTr("Open In Steam")
+ font.pointSize: 10
+ color: "white"
+ font.underline: true
+ font.family: ScreenPlay.settings.font
+ font.weight: Font.Thin
+ }
+ }
+ }
+ }
+ }
+
+ GridView {
+ id: gridView
+ maximumFlickVelocity: 7000
+ flickDeceleration: 5000
+ cellWidth: 330
+ cellHeight: 190
+ height: contentHeight
+ interactive: false
+ model: Workshop.steamWorkshop.workshopListModel
+ anchors {
+ top: header.bottom
+ topMargin: 100
+ left: parent.left
+ right: parent.right
+ leftMargin: 50
+ }
+
+ header: Item {
+ height: 70
+ width: parent.width
+
+ Item {
+ id: searchWrapper
+
+ width: 400
+ height: 45
+
+ anchors {
+ top: parent.top
+ left: parent.left
+ }
+
+ Rectangle {
+ anchors.fill: parent
+ color: Material.theme === Material.Light ? "white" : Qt.darker(
+ Material.background)
+ opacity: .95
+ radius: 3
+ }
+
+ TextField {
+ id: tiSearch
+ anchors {
+ top: parent.top
+ right: parent.right
+ rightMargin: 10
+ bottom: parent.bottom
+ left: parent.left
+ leftMargin: 10
+ }
+ placeholderText: qsTr("Search for Wallpaper and Widgets...")
+ placeholderTextColor: "#666666"
+ font.pointSize: 10
+ font.family: ScreenPlay.settings.font
+ color: "white"
+ onTextChanged: timerSearch.restart()
+ Timer {
+ id: timerSearch
+ interval: 300
+ onTriggered: Workshop.steamWorkshop.workshopListModel.searchWorkshopByText(
+ tiSearch.text)
+ }
+ }
+ }
+
+ ComboBox {
+ id: cbQuerySort
+ width: 250
+ height: searchWrapper.height
+ anchors {
+ verticalCenter: parent.verticalCenter
+ right: parent.right
+ rightMargin: 50
+ }
+
+ textRole: "text"
+ valueRole: "value"
+ currentIndex: 2
+ Layout.preferredHeight: searchWrapper.height
+ font.family: ScreenPlay.settings.font
+ onActivated: {
+ Workshop.steamWorkshop.workshopListModel.searchWorkshop(
+ cbQuerySort.currentValue)
+ }
+ model: [{
+ "value": SteamEnums.k_EUGCQuery_RankedByVote,
+ "text": qsTr("Ranked By Vote")
+ }, {
+ "value": SteamEnums.K_EUGCQuery_RankedByPublicationDate,
+ "text": qsTr("Publication Date")
+ }, {
+ "value": SteamEnums.K_EUGCQuery_RankedByTrend,
+ "text": qsTr("Ranked By Trend")
+ }, {
+ "value": SteamEnums.K_EUGCQuery_FavoritedByFriendsRankedByPublicationDate,
+ "text": qsTr("Favorited By Friends")
+ }, {
+ "value": SteamEnums.K_EUGCQuery_CreatedByFriendsRankedByPublicationDate,
+ "text": qsTr("Created By Friends")
+ }, {
+ "value": SteamEnums.K_EUGCQuery_CreatedByFollowedUsersRankedByPublicationDate,
+ "text": qsTr("Created By Followed Users")
+ }, {
+ "value": SteamEnums.K_EUGCQuery_NotYetRated,
+ "text": qsTr("Not Yet Rated")
+ }, {
+ "value": SteamEnums.K_EUGCQuery_RankedByTotalVotesAsc,
+ "text": qsTr("Total VotesAsc")
+ }, {
+ "value": SteamEnums.K_EUGCQuery_RankedByVotesUp,
+ "text": qsTr("Votes Up")
+ }, {
+ "value": SteamEnums.K_EUGCQuery_RankedByTotalUniqueSubscriptions,
+ "text": qsTr("Total Unique Subscriptions")
+ }]
+ }
+ }
+
+ boundsBehavior: Flickable.StopAtBounds
+
+ delegate: WorkshopItem {
+ imgUrl: m_workshopPreview
+ name: m_workshopTitle
+ workshopID: m_workshopID
+ additionalPreviewUrl: m_additionalPreviewUrl
+ subscriptionCount: m_subscriptionCount
+ itemIndex: index
+ onClicked: {
+ workshopItemDetail.setWorkshopItem(
+ workshopID, imgUrl, additionalPreviewUrl,
+ subscriptionCount)
+ }
+ }
+
+ ScrollBar.vertical: ScrollBar {
+ id: workshopScrollBar
+ snapMode: ScrollBar.SnapOnRelease
+ }
+ }
+ }
+ }
+
+ WorkshopItemDetail {
+ id: workshopItemDetail
+ topMargin: 60
+ }
+
+ states: [
+ State {
+ name: "base"
+
+ ParentChange {
+ target: nav
+ parent: wrapper
+ }
+
+ PropertyChanges {
+ target: nav
+ anchors.top: wrapper.top
+ anchors.topMargin: header.height
+ width: 800
+ state: "base"
+ }
+ },
+ State {
+ name: "scrolling"
+ ParentChange {
+ target: nav
+ parent: workshop
+ }
+ PropertyChanges {
+ target: nav
+ anchors.topMargin: 0
+ anchors.top: workshop.top
+ width: wrapper.width
+ state: "scrolling"
+ }
+ }
+ ]
+
+ transitions: [
+ Transition {
+ from: "base"
+ to: "scrolling"
+ PropertyAnimation {
+ target: nav
+ properties: "width"
+ duration: 100
+ }
+ },
+ Transition {
+ from: "scrolling"
+ to: "base"
+
+ PropertyAnimation {
+ target: nav
+ properties: "width,x,y"
+ duration: 300
+ }
+ }
+ ]
+}
+
+/*##^## Designer {
+ D{i:0;autoSize:true;height:800;width:1366}
+}
+ ##^##*/
+
diff --git a/ScreenPlay/qml/Workshop/upload/PopupSteamWorkshopAgreement.qml b/ScreenPlay/qml/Workshop/upload/PopupSteamWorkshopAgreement.qml
new file mode 100644
index 00000000..3d4b6a3a
--- /dev/null
+++ b/ScreenPlay/qml/Workshop/upload/PopupSteamWorkshopAgreement.qml
@@ -0,0 +1,38 @@
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Controls.Material 2.12
+import QtQuick.Layouts 1.12
+
+import ScreenPlay.Workshop 1.0 as SP
+import ScreenPlay 1.0
+
+Popup {
+ id: popupSteamWorkshopAgreement
+ dim: true
+ width: 1100
+ height: 600
+ closePolicy: Popup.NoAutoClose
+ anchors.centerIn: Overlay.overlay
+ background: Rectangle {
+ color: Material.theme === Material.Light ? "white" : Material.background
+ }
+
+ Button {
+ id:btnAbort
+ text: qsTr("Abort Upload.")
+ onClicked: {
+
+ }
+ }
+
+ Button {
+ id:btnAgree
+ text: qsTr("I Agree to the Steam Workshop Agreement")
+ highlighted: true
+ Material.background: Material.accent
+ Material.foreground: "white"
+ onClicked: {
+
+ }
+ }
+}
diff --git a/ScreenPlay/qml/Workshop/upload/UploadProject.qml b/ScreenPlay/qml/Workshop/upload/UploadProject.qml
new file mode 100644
index 00000000..ff46f6be
--- /dev/null
+++ b/ScreenPlay/qml/Workshop/upload/UploadProject.qml
@@ -0,0 +1,248 @@
+import QtQuick 2.12
+import QtQuick.Controls 2.12
+import QtQuick.Controls.Material 2.12
+import QtQuick.Layouts 1.12
+
+import ScreenPlay.Workshop 1.0 as SP
+import ScreenPlay 1.0
+
+Popup {
+ id: root
+ width: 1100
+ height: 600
+ modal: true
+ dim: true
+ closePolicy: Popup.NoAutoClose
+// anchors.centerIn: Overlay.overlay
+ onAboutToShow: uploadLoader.sourceComponent = com
+ onAboutToHide: uploadLoader.sourceComponent = undefined
+ background: Rectangle {
+ color: Material.theme === Material.Light ? "white" : Material.background
+ }
+
+ Loader {
+ id: uploadLoader
+ anchors.fill: parent
+ }
+
+ Connections {
+ target: uploadLoader.item
+ function onRequestClosePopup() {
+ root.close()
+ }
+ }
+
+ Connections {
+ target: SP.Workshop.steamWorkshop.uploadListModel
+ function onUserNeedsToAcceptWorkshopLegalAgreement() {
+ popupSteamWorkshopAgreement.open()
+ }
+ }
+
+ PopupSteamWorkshopAgreement {
+ id: popupSteamWorkshopAgreement
+ }
+
+ Component {
+ id: com
+ Item {
+ id: wrapper
+ signal requestClosePopup
+
+ Item {
+ id: headerWrapper
+ height: 50
+ anchors {
+ top: parent.top
+ right: parent.right
+ left: parent.left
+ margins: 10
+ }
+
+ Text {
+ id: txtHeadline
+ text: qsTr("Upload Wallpaper/Widgets to Steam")
+ color: Material.foreground
+ font.pointSize: 21
+ font.family: ScreenPlay.settings.font
+ font.weight: Font.Thin
+
+ anchors {
+ top: parent.top
+ horizontalCenter: parent.horizontalCenter
+ }
+ }
+ }
+
+ SwipeView {
+ id: view
+ clip: true
+ currentIndex: 0
+ anchors {
+ top: headerWrapper.bottom
+ right: parent.right
+ bottom: parent.bottom
+ left: parent.left
+ margins: 10
+ }
+ interactive: false
+
+ Item {
+ id: firstPage
+
+ GridView {
+ id: gridView
+ boundsBehavior: Flickable.DragOverBounds
+ maximumFlickVelocity: 7000
+ flickDeceleration: 5000
+ cellWidth: parent.width
+ cellHeight: 250
+ clip: true
+ model: SP.Workshop.installedListModel
+ anchors {
+ top: parent.top
+ right: parent.right
+ bottom: btnAbort.top
+ left: parent.left
+ margins: 10
+ }
+ delegate: UploadProjectBigItem {
+ id: delegate
+ focus: true
+ width: gridView.cellWidth - 30
+ customTitle: screenTitle
+ type: screenType
+ screenId: screenFolderId
+ absoluteStoragePath: screenAbsoluteStoragePath
+ workshopID: screenWorkshopID
+ preview: screenPreview
+ itemIndex: index
+ onItemClicked: {
+ for (let childItem in gridView.contentItem.children) {
+ if (gridView.contentItem.children[childItem].isSelected) {
+ btnUploadProjects.enabled = true
+ return
+ }
+ }
+ btnUploadProjects.enabled = false
+ }
+ }
+
+ ScrollBar.vertical: ScrollBar {
+ snapMode: ScrollBar.SnapOnRelease
+ policy: ScrollBar.AlwaysOn
+ }
+ }
+ Button {
+ id:btnAbort
+ text: qsTr("Abort")
+ onClicked: {
+ SP.Workshop.steamWorkshop.uploadListModel.clear()
+ wrapper.requestClosePopup()
+ }
+
+ anchors {
+ right: btnUploadProjects.left
+ bottom: parent.bottom
+ margins: 10
+ }
+ }
+
+ Button {
+ id: btnUploadProjects
+ text: qsTr("Upload Projects")
+ highlighted: true
+ enabled: false
+ anchors {
+ right: parent.right
+ bottom: parent.bottom
+
+ margins: 10
+ }
+
+ onClicked: {
+ var uploadListArray = []
+ for (let childItem in gridView.contentItem.children) {
+ if (gridView.contentItem.children[childItem].isSelected) {
+
+ uploadListArray.push(
+ gridView.contentItem.children[childItem].absoluteStoragePath)
+ }
+ }
+ view.currentIndex = 1
+ SP.Workshop.steamWorkshop.bulkUploadToWorkshop(
+ uploadListArray)
+ }
+ }
+ }
+ Item {
+ id: secondPage
+
+ ListView {
+ id: listView
+ boundsBehavior: Flickable.DragOverBounds
+ maximumFlickVelocity: 7000
+ flickDeceleration: 5000
+ cacheBuffer: 1000
+ clip: true
+ model: SP.Workshop.steamWorkshop.uploadListModel
+ width: parent.width - 50
+ spacing: 25
+ anchors {
+ top: parent.top
+ horizontalCenter: parent.horizontalCenter
+ bottom: parent.bottom
+ margins: 10
+ }
+
+ delegate: UploadProjectItem {
+
+ previewImagePath: _absolutePreviewImagePath
+ progress: _uploadProgress
+ name: _name
+ steamStatus: _status
+ }
+
+ ScrollBar.vertical: ScrollBar {
+ snapMode: ScrollBar.SnapOnRelease
+ }
+ }
+
+ Button {
+ id: btnFinish
+ text: qsTr("Finish")
+ onClicked: {
+ SP.Workshop.steamWorkshop.uploadListModel.clear()
+ wrapper.requestClosePopup()
+ }
+ highlighted: true
+ enabled: false
+ anchors {
+ right: parent.right
+ bottom: parent.bottom
+ margins: 10
+ }
+ Connections {
+ target: SP.Workshop.steamWorkshop.uploadListModel
+ function onUploadCompleted() {
+ btnFinish.enabled = true
+ }
+ }
+ }
+ }
+
+
+ }
+
+ PageIndicator {
+ id: indicator
+
+ count: view.count
+ currentIndex: view.currentIndex
+
+ anchors.bottom: view.bottom
+ anchors.horizontalCenter: parent.horizontalCenter
+ }
+ }
+ }
+}
diff --git a/ScreenPlay/qml/Workshop/upload/UploadProjectBigItem.qml b/ScreenPlay/qml/Workshop/upload/UploadProjectBigItem.qml
new file mode 100644
index 00000000..fbc688dd
--- /dev/null
+++ b/ScreenPlay/qml/Workshop/upload/UploadProjectBigItem.qml
@@ -0,0 +1,211 @@
+import QtQuick 2.12
+import QtGraphicalEffects 1.0
+import QtQuick.Controls 2.3
+import QtQuick.Controls.Material 2.12
+import QtQuick.Layouts 1.12
+import ScreenPlay 1.0
+
+import "../"
+
+Item {
+ id: root
+
+ height: 250
+ property bool isProjectValid: false
+
+ property alias checkBox: checkBox
+ property bool isSelected: false
+ property string customTitle: "name here"
+ property string absoluteStoragePath: ""
+ property string screenId: ""
+ property string preview: ""
+ property string type: ""
+ property bool hasMenuOpen: false
+ property int workshopID: 0
+ property int itemIndex
+ signal itemClicked(var screenId, var type, var isActive)
+
+ onTypeChanged: {
+ if (type === "widget") {
+ icnType.source = "icons/icon_widgets.svg"
+ } else if (type === "qmlScene") {
+ icnType.source = "icons/icon_code.svg"
+ }
+ }
+// Component.onCompleted: {
+// print("root.preview",root.preview)
+// if (root.preview == undefined) {
+// print("invalid")
+// } else {
+// root.isProjectValid = true
+// }
+
+// if (!isProjectValid) {
+// root.state = "invalid"
+// }
+// }
+
+ Rectangle {
+ id: screenPlayItemWrapper
+ color: Material.theme === Material.Light ? "white" : Qt.darker(
+ Material.background)
+ anchors.fill: parent
+ anchors.margins: 20
+
+ Item {
+ id: itemWrapper
+ width: parent.width
+ height: parent.height
+ clip: true
+
+ Image {
+ id: screenPlayItemImage
+ width: 400
+ anchors {
+ top: parent.top
+ left: parent.left
+ bottom: parent.bottom
+ }
+ source: Qt.resolvedUrl(
+ root.absoluteStoragePath + "/" + root.preview)
+ }
+
+ Image {
+ id: icnType
+ width: 20
+ height: 20
+ sourceSize: Qt.size(20, 20)
+ anchors {
+ top: parent.top
+ left: parent.left
+ margins: 10
+ }
+ }
+
+ ColumnLayout {
+ anchors {
+ top: parent.top
+ right: parent.right
+ left: screenPlayItemImage.right
+ margins: 20
+ }
+ spacing: 10
+
+ Text {
+ id: name
+ text: screenTitle
+ color: Material.foreground
+ font.pointSize: 18
+ font.family: ScreenPlay.settings.font
+ font.weight: Font.Thin
+ }
+
+ Text {
+ text: qsTr("Type: ") + screenType
+ color: Material.foreground
+ font.family: ScreenPlay.settings.font
+ }
+ }
+
+ Button {
+ text: qsTr("Open Folder")
+ onClicked: ScreenPlay.util.openFolderInExplorer(
+ screenAbsoluteStoragePath)
+ anchors {
+ right: parent.right
+ bottom: parent.bottom
+ margins: 20
+ }
+ }
+
+ Rectangle {
+ id: rctInvalid
+ anchors.fill: parent
+ color: screenPlayItemWrapper.color
+ opacity: 0
+ visible: false
+ }
+
+ Text {
+ id: txtInvalidError
+ text: qsTr("Invalid Project!")
+ color: Material.color(Material.Red)
+ anchors.fill: screenPlayItemImage
+ font.pointSize: 18
+ font.family: ScreenPlay.settings.font
+ font.weight: Font.Thin
+ opacity: 0
+ }
+ }
+
+ CheckBox {
+ id: checkBox
+ onCheckStateChanged: {
+ if (checkState == Qt.Checked) {
+ isSelected = true
+ } else {
+ isSelected = false
+ }
+ itemClicked(screenId, type, isSelected)
+ }
+
+ anchors {
+ top: parent.top
+ right: parent.right
+ margins: 10
+ }
+ }
+ }
+
+ states: [
+ State {
+ name: "selected"
+
+ PropertyChanges {
+ target: screenPlayItemWrapper
+ y: 0
+ opacity: 1
+ }
+ PropertyChanges {
+ target: icnType
+ opacity: .5
+ }
+ },
+ State {
+ name: "invalid"
+
+ PropertyChanges {
+ target: checkBox
+ enabled: false
+ }
+ PropertyChanges {
+ target: txtInvalidError
+ opacity: 1
+ }
+
+ PropertyChanges {
+ target: rctInvalid
+ opacity: .8
+ visible: true
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ from: "*"
+ to: "invalid"
+ PropertyAnimation {
+ property: opacity
+ target: txtInvalidError
+ duration: 250
+ }
+ }
+ ]
+}
+
+/*##^##
+Designer {
+ D{i:0;formeditorZoom:0.6600000262260437;height:250;width:600}
+}
+##^##*/
+
diff --git a/ScreenPlay/qml/Workshop/upload/UploadProjectItem.qml b/ScreenPlay/qml/Workshop/upload/UploadProjectItem.qml
new file mode 100644
index 00000000..92c88a7b
--- /dev/null
+++ b/ScreenPlay/qml/Workshop/upload/UploadProjectItem.qml
@@ -0,0 +1,534 @@
+import QtQuick 2.13
+import QtQuick.Controls 2.13
+
+import QtGraphicalEffects 1.0
+import QtQuick.Controls.Material 2.12
+
+import ScreenPlay.Workshop.SteamEnums 1.0
+import QtQuick.Layouts 1.12
+
+Page {
+ id: root
+ background: Rectangle {
+ color: "#333333"
+ // color: Material.theme === Material.Light ? Material.background : Qt.darker(
+ // Material.background)
+ radius: 3
+ }
+
+ padding: 20
+ height: 240
+
+ property string previewImagePath
+ onPreviewImagePathChanged: img.source = Qt.resolvedUrl(
+ "file:///" + previewImagePath)
+ property real progress: 0.5
+ property string name: "Headline"
+ property var steamStatus
+ onSteamStatusChanged: {
+ let errorText
+ switch (steamStatus) {
+ case SteamEnums.K_EResultNone:
+ root.contentItem.state = "uploadComplete"
+ return
+ // Everyting that is not OK is a fail. See steam_qt_enums_generated.h
+ case SteamEnums.K_EResultFail:
+ errorText = qsTr("Fail")
+ break
+ case SteamEnums.K_EResultNoConnection:
+ errorText = qsTr("No Connection")
+ break
+ case SteamEnums.K_EResultInvalidPassword:
+ errorText = qsTr("Invalid Password")
+ break
+ case SteamEnums.K_EResultLoggedInElsewhere:
+ errorText = qsTr("Logged In Elsewhere")
+ break
+ case SteamEnums.K_EResultInvalidProtocolVer:
+ errorText = qsTr("Invalid Protocol Version")
+ break
+ case SteamEnums.K_EResultInvalidParam:
+ errorText = qsTr("Invalid Param")
+ break
+ case SteamEnums.K_EResultFileNotFound:
+ errorText = qsTr("File Not Found")
+ break
+ case SteamEnums.K_EResultBusy:
+ errorText = qsTr("Busy")
+ break
+ case SteamEnums.K_EResultInvalidState:
+ errorText = qsTr("Invalid State")
+ break
+ case SteamEnums.K_EResultInvalidName:
+ errorText = qsTr("Invalid Name")
+ break
+ case SteamEnums.K_EResultInvalidEmail:
+ errorText = qsTr("Invalid Email")
+ break
+ case SteamEnums.K_EResultDuplicateName:
+ errorText = qsTr("Duplicate Name")
+ break
+ case SteamEnums.K_EResultAccessDenied:
+ errorText = qsTr("Access Denied")
+ break
+ case SteamEnums.K_EResultTimeout:
+ errorText = qsTr("Timeout")
+ break
+ case SteamEnums.K_EResultBanned:
+ errorText = qsTr("Banned")
+ break
+ case SteamEnums.K_EResultAccountNotFound:
+ errorText = qsTr("Account Not Found")
+ break
+ case SteamEnums.K_EResultInvalidSteamID:
+ errorText = qsTr("Invalid SteamID")
+ break
+ case SteamEnums.K_EResultServiceUnavailable:
+ errorText = qsTr("Service Unavailable")
+ break
+ case SteamEnums.K_EResultNotLoggedOn:
+ errorText = qsTr("Not Logged On")
+ break
+ case SteamEnums.K_EResultPending:
+ errorText = qsTr("Pending")
+ break
+ case SteamEnums.K_EResultEncryptionFailure:
+ errorText = qsTr("Encryption Failure")
+ break
+ case SteamEnums.K_EResultInsufficientPrivilege:
+ errorText = qsTr("Insufficient Privilege")
+ break
+ case SteamEnums.K_EResultLimitExceeded:
+ errorText = qsTr("Limit Exceeded")
+ break
+ case SteamEnums.K_EResultRevoked:
+ errorText = qsTr("Revoked")
+ break
+ case SteamEnums.K_EResultExpired:
+ errorText = qsTr("Expired")
+ break
+ case SteamEnums.K_EResultAlreadyRedeemed:
+ errorText = qsTr("Already Redeemed")
+ break
+ case SteamEnums.K_EResultDuplicateRequest:
+ errorText = qsTr("Duplicate Request")
+ break
+ case SteamEnums.K_EResultAlreadyOwned:
+ errorText = qsTr("Already Owned")
+ break
+ case SteamEnums.K_EResultIPNotFound:
+ errorText = qsTr("IP Not Found")
+ break
+ case SteamEnums.K_EResultPersistFailed:
+ errorText = qsTr("Persist Failed")
+ break
+ case SteamEnums.K_EResultLockingFailed:
+ errorText = qsTr("Locking Failed")
+ break
+ case SteamEnums.K_EResultLogonSessionReplaced:
+ errorText = qsTr("Logon Session Replaced")
+ break
+ case SteamEnums.K_EResultConnectFailed:
+ errorText = qsTr("Connect Failed")
+ break
+ case SteamEnums.K_EResultHandshakeFailed:
+ errorText = qsTr("Handshake Failed")
+ break
+ case SteamEnums.K_EResultIOFailure:
+ errorText = qsTr("IO Failure")
+ break
+ case SteamEnums.K_EResultRemoteDisconnect:
+ errorText = qsTr("Remote Disconnect")
+ break
+ case SteamEnums.K_EResultShoppingCartNotFound:
+ errorText = qsTr("Shopping Cart Not Found")
+ break
+ case SteamEnums.K_EResultBlocked:
+ errorText = qsTr("Blocked")
+ break
+ case SteamEnums.K_EResultIgnored:
+ errorText = qsTr("Ignored")
+ break
+ case SteamEnums.K_EResultNoMatch:
+ errorText = qsTr("No Match")
+ break
+ case SteamEnums.K_EResultAccountDisabled:
+ errorText = qsTr("Account Disabled")
+ break
+ case SteamEnums.K_EResultServiceReadOnly:
+ errorText = qsTr("Service ReadOnly")
+ break
+ case SteamEnums.K_EResultAccountNotFeatured:
+ errorText = qsTr("Account Not Featured")
+ break
+ case SteamEnums.K_EResultAdministratorOK:
+ errorText = qsTr("Administrator OK")
+ break
+ case SteamEnums.K_EResultContentVersion:
+ errorText = qsTr("Content Version")
+ break
+ case SteamEnums.K_EResultTryAnotherCM:
+ errorText = qsTr("Try Another CM")
+ break
+ case SteamEnums.K_EResultPasswordRequiredToKickSession:
+ errorText = qsTr("Password Required T oKick Session")
+ break
+ case SteamEnums.K_EResultAlreadyLoggedInElsewhere:
+ errorText = qsTr("Already Logged In Elsewhere")
+ break
+ case SteamEnums.K_EResultSuspended:
+ errorText = qsTr("Suspended")
+ break
+ case SteamEnums.K_EResultCancelled:
+ errorText = qsTr("Cancelled")
+ break
+ case SteamEnums.K_EResultDataCorruption:
+ errorText = qsTr("Data Corruption")
+ break
+ case SteamEnums.K_EResultDiskFull:
+ errorText = qsTr("Disk Full")
+ break
+ case SteamEnums.K_EResultRemoteCallFailed:
+ errorText = qsTr("Remote Call Failed")
+ break
+ case SteamEnums.K_EResultPasswordUnset:
+ errorText = qsTr("Password Unset")
+ break
+ case SteamEnums.K_EResultExternalAccountUnlinked:
+ errorText = qsTr("External Account Unlinked")
+ break
+ case SteamEnums.K_EResultPSNTicketInvalid:
+ errorText = qsTr("PSN Ticket Invalid")
+ break
+ case SteamEnums.K_EResultExternalAccountAlreadyLinked:
+ errorText = qsTr("External Account Already Linked")
+ break
+ case SteamEnums.K_EResultRemoteFileConflict:
+ errorText = qsTr("Remote File Conflict")
+ break
+ case SteamEnums.K_EResultIllegalPassword:
+ errorText = qsTr("Illegal Password")
+ break
+ case SteamEnums.K_EResultSameAsPreviousValue:
+ errorText = qsTr("Same As Previous Value")
+ break
+ case SteamEnums.K_EResultAccountLogonDenied:
+ errorText = qsTr("Account Logon Denied")
+ break
+ case SteamEnums.K_EResultCannotUseOldPassword:
+ errorText = qsTr("Cannot Use Old Password")
+ break
+ case SteamEnums.K_EResultInvalidLoginAuthCode:
+ errorText = qsTr("Invalid Login AuthCode")
+ break
+ case SteamEnums.K_EResultAccountLogonDeniedNoMail:
+ errorText = qsTr("Account Logon Denied No Mail")
+ break
+ case SteamEnums.K_EResultHardwareNotCapableOfIPT:
+ errorText = qsTr("Hardware Not Capable Of IPT")
+ break
+ case SteamEnums.K_EResultIPTInitError:
+ errorText = qsTr("IPT Init Error")
+ break
+ case SteamEnums.K_EResultParentalControlRestricted:
+ errorText = qsTr("Parental Control Restricted")
+ break
+ case SteamEnums.K_EResultFacebookQueryError:
+ errorText = qsTr("Facebook Query Error")
+ break
+ case SteamEnums.K_EResultExpiredLoginAuthCode:
+ errorText = qsTr("Expired Login Auth Code")
+ break
+ case SteamEnums.K_EResultIPLoginRestrictionFailed:
+ errorText = qsTr("IP Login Restriction Failed")
+ break
+ case SteamEnums.K_EResultAccountLockedDown:
+ errorText = qsTr("Account Locked Down")
+ break
+ case SteamEnums.K_EResultAccountLogonDeniedVerifiedEmailRequired:
+ errorText = qsTr("Account Logon Denied Verified Email Required")
+ break
+ case SteamEnums.K_EResultNoMatchingURL:
+ errorText = qsTr("No MatchingURL")
+ break
+ case SteamEnums.K_EResultBadResponse:
+ errorText = qsTr("Bad Response")
+ break
+ case SteamEnums.K_EResultRequirePasswordReEntry:
+ errorText = qsTr("Require Password ReEntry")
+ break
+ case SteamEnums.K_EResultValueOutOfRange:
+ errorText = qsTr("Value Out Of Range")
+ break
+ case SteamEnums.K_EResultUnexpectedError:
+ errorText = qsTr("Unexpecte Error")
+ break
+ case SteamEnums.K_EResultDisabled:
+ errorText = qsTr("Disabled")
+ break
+ case SteamEnums.K_EResultInvalidCEGSubmission:
+ errorText = qsTr("Invalid CEG Submission")
+ break
+ case SteamEnums.K_EResultRestrictedDevice:
+ errorText = qsTr("Restricted Device")
+ break
+ case SteamEnums.K_EResultRegionLocked:
+ errorText = qsTr("Region Locked")
+ break
+ case SteamEnums.K_EResultRateLimitExceeded:
+ errorText = qsTr("Rate Limit Exceeded")
+ break
+ case SteamEnums.K_EResultAccountLoginDeniedNeedTwoFactor:
+ errorText = qsTr("Account Login Denied Need Two Factor")
+ break
+ case SteamEnums.K_EResultItemDeleted:
+ errorText = qsTr("Item Deleted")
+ break
+ case SteamEnums.K_EResultAccountLoginDeniedThrottle:
+ errorText = qsTr("Account Login Denied Throttle")
+ break
+ case SteamEnums.K_EResultTwoFactorCodeMismatch:
+ errorText = qsTr("Two Factor Code Mismatch")
+ break
+ case SteamEnums.K_EResultTwoFactorActivationCodeMismatch:
+ errorText = qsTr("Two Factor Activation Code Mismatch")
+ break
+ case SteamEnums.K_EResultAccountAssociatedToMultiplePartners:
+ errorText = qsTr("Account Associated To Multiple Partners")
+ break
+ case SteamEnums.K_EResultNotModified:
+ errorText = qsTr("Not Modified")
+ break
+ case SteamEnums.K_EResultNoMobileDevice:
+ errorText = qsTr("No Mobile Device")
+ break
+ case SteamEnums.K_EResultTimeNotSynced:
+ errorText = qsTr("Time Not Synced")
+ break
+ case SteamEnums.K_EResultSmsCodeFailed:
+ errorText = qsTr("Sms Code Failed")
+ break
+ case SteamEnums.K_EResultAccountLimitExceeded:
+ errorText = qsTr("Account Limit Exceeded")
+ break
+ case SteamEnums.K_EResultAccountActivityLimitExceeded:
+ errorText = qsTr("Account Activity Limit Exceeded")
+ break
+ case SteamEnums.K_EResultPhoneActivityLimitExceeded:
+ errorText = qsTr("Phone Activity Limit Exceeded")
+ break
+ case SteamEnums.K_EResultRefundToWallet:
+ errorText = qsTr("Refund To Wallet")
+ break
+ case SteamEnums.K_EResultEmailSendFailure:
+ errorText = qsTr("Email Send Failure")
+ break
+ case SteamEnums.K_EResultNotSettled:
+ errorText = qsTr("Not Settled")
+ break
+ case SteamEnums.K_EResultNeedCaptcha:
+ errorText = qsTr("Need Captcha")
+ break
+ case SteamEnums.K_EResultGSLTDenied:
+ errorText = qsTr("GSLT Denied")
+ break
+ case SteamEnums.K_EResultGSOwnerDenied:
+ errorText = qsTr("GS Owner Denied")
+ break
+ case SteamEnums.K_EResultInvalidItemType:
+ errorText = qsTr("Invalid Item Type")
+ break
+ case SteamEnums.K_EResultIPBanned:
+ errorText = qsTr("IP Banned")
+ break
+ case SteamEnums.K_EResultGSLTExpired:
+ errorText = qsTr("GSLT Expired")
+ break
+ case SteamEnums.K_EResultInsufficientFunds:
+ errorText = qsTr("Insufficient Funds")
+ break
+ case SteamEnums.K_EResultTooManyPending:
+ errorText = qsTr("Too Many Pending")
+ break
+ case SteamEnums.K_EResultNoSiteLicensesFound:
+ errorText = qsTr("No Site Licenses Found")
+ break
+ case SteamEnums.K_EResultWGNetworkSendExceeded:
+ errorText = qsTr("WG Network Send Exceeded")
+ break
+ case SteamEnums.K_EResultAccountNotFriends:
+ errorText = qsTr("Account Not Friends")
+ break
+ case SteamEnums.K_EResultLimitedUserAccount:
+ errorText = qsTr("Limited User Account")
+ break
+ case SteamEnums.K_EResultCantRemoveItem:
+ errorText = qsTr("Cant Remove Item")
+ break
+ case SteamEnums.K_EResultAccountDeleted:
+ errorText = qsTr("Account Deleted")
+ break
+ case SteamEnums.K_EResultExistingUserCancelledLicense:
+ errorText = qsTr("Existing User Cancelled License")
+ break
+ case SteamEnums.K_EResultCommunityCooldown:
+ errorText = qsTr("Community Cooldown")
+ break
+ }
+ root.contentItem.txtStatus.statusText = errorText
+ root.contentItem.state = "error"
+ }
+
+ contentItem: Item {
+ anchors.fill: parent
+ state: "base"
+ Image {
+ id: img
+ width: 300
+ anchors {
+ top: parent.top
+ left: parent.left
+ bottom: parent.bottom
+ }
+ LinearGradient {
+ id: gradient
+ height: parent.height
+ cached: true
+ opacity: 0
+ anchors.fill: parent
+ start: Qt.point(0, height)
+ end: Qt.point(0, 0)
+ gradient: Gradient {
+ GradientStop {
+ id: gradientStop0
+ position: 0.0
+ color: "#DD000000"
+ }
+ GradientStop {
+ id: gradientStop1
+ position: 1.0
+ color: "#00000000"
+ }
+ }
+ }
+ }
+
+ ColumnLayout {
+ spacing: 10
+ anchors {
+ top: parent.top
+ right: parent.right
+ left: img.right
+ margins: 20
+ }
+ Text {
+ id: name
+ text: root.name
+ verticalAlignment: Text.AlignVCenter
+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
+ color: "white"
+ font.pointSize: 18
+ Layout.preferredHeight: 30
+ Layout.fillWidth: true
+ }
+
+ Text {
+ id: txtStatus
+ property string statusText: "Loading..."
+ text: qsTr("Status:") + " " + statusText
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
+ color: "white"
+ font.pointSize: 14
+ Layout.preferredHeight: 30
+ }
+
+ Item {
+ Layout.preferredHeight: 60
+ Layout.fillWidth: true
+ }
+ ColumnLayout {
+ spacing: 10
+ Layout.fillWidth: true
+ Text {
+ text: qsTr("Upload Progress: ") + " " + Math.ceil(
+ root.progress * 100) + "%"
+ verticalAlignment: Text.AlignVCenter
+ horizontalAlignment: Text.AlignHCenter
+ wrapMode: Text.WrapAtWordBoundaryOrAnywhere
+
+ color: "white"
+ font.pointSize: 14
+ height: 50
+ }
+
+ ProgressBar {
+ id: progressBar
+ Layout.fillWidth: true
+ value: root.progress
+ }
+ }
+ }
+
+ states: [
+
+ State {
+ name: "uploading"
+ PropertyChanges {}
+ },
+ State {
+ name: "uploadComplete"
+ PropertyChanges {
+ target: gradient
+ opacity: .7
+ }
+ PropertyChanges {
+ target: gradient
+ opacity: .7
+ }
+ PropertyChanges {
+ target: gradientStop0
+ color: Material.color(Material.Lime)
+ }
+ PropertyChanges {
+ target: gradientStop1
+ color: Material.color(Material.LightGreen)
+ }
+ },
+ State {
+ name: "error"
+ PropertyChanges {
+ target: gradient
+ opacity: .7
+ }
+ PropertyChanges {
+ target: gradientStop0
+ color: Material.color(Material.Red)
+ }
+ PropertyChanges {
+ target: gradientStop1
+ color: Material.color(Material.DeepOrange)
+ }
+ }
+ ]
+ transitions: [
+ Transition {
+ from: "base"
+ to: "uploading"
+
+ PropertyAnimation {
+ targets: [gradient, gradientStop0, gradientStop1]
+ duration: 500
+ }
+ }
+ ]
+ }
+}
+
+/*##^##
+Designer {
+ D{i:0;height:240;width:800}
+}
+##^##*/
+