diff --git a/.gitignore b/.gitignore index 8553f87..96f406a 100644 --- a/.gitignore +++ b/.gitignore @@ -370,3 +370,5 @@ MigrationBackup/ # Fody - auto-generated XML schema FodyWeavers.xsd .visuallint +GlosSIConfig/steamgrid_api_keys.h +steamgrid.zip diff --git a/GlosSIConfig/GlosSIConfig.vcxproj b/GlosSIConfig/GlosSIConfig.vcxproj index b649a7b..a79c58d 100644 --- a/GlosSIConfig/GlosSIConfig.vcxproj +++ b/GlosSIConfig/GlosSIConfig.vcxproj @@ -145,6 +145,7 @@ + @@ -163,6 +164,7 @@ + diff --git a/GlosSIConfig/GlosSIConfig.vcxproj.filters b/GlosSIConfig/GlosSIConfig.vcxproj.filters index 08d81b8..9811199 100644 --- a/GlosSIConfig/GlosSIConfig.vcxproj.filters +++ b/GlosSIConfig/GlosSIConfig.vcxproj.filters @@ -83,6 +83,9 @@ qml + + qml + @@ -102,6 +105,9 @@ Header Files + + Header Files + diff --git a/GlosSIConfig/UIModel.cpp b/GlosSIConfig/UIModel.cpp index 873304c..c23a67b 100644 --- a/GlosSIConfig/UIModel.cpp +++ b/GlosSIConfig/UIModel.cpp @@ -33,6 +33,7 @@ limitations under the License. #endif #include "../version.hpp" +#include "steamgrid_api_keys.h" UIModel::UIModel() : QObject(nullptr) { @@ -479,6 +480,17 @@ QVariantList UIModel::egsGamesList() const return {{"InstallLocation", "Error"}}; } +void UIModel::loadSteamGridImages() +{ + std::filesystem::path path = QCoreApplication::applicationDirPath().toStdWString(); + path /= "steamgrid.exe"; + + steamgrid_proc_.setProgram(path.string().c_str()); + steamgrid_proc_.setArguments({"-nonsteamonly", "--onlymissingartwork", "--steamgriddb", steamgridb_key}); + connect(&steamgrid_proc_, &QProcess::readyReadStandardOutput, this, &UIModel::onSteamGridReadReady); + steamgrid_proc_.start(); + steamgrid_proc_.write("\n"); +} QString UIModel::getGridImagePath(QVariant shortcut) const { @@ -497,9 +509,9 @@ QString UIModel::getGridImagePath(QVariant shortcut) const } const std::vector extensions = {".png", ".jpg"}; for (const auto& entry : std::filesystem::directory_iterator(grid_dir)) { - if (entry.is_regular_file() - && std::ranges::find(extensions, entry.path().extension().string()) != extensions.end() - && entry.path().filename().string().find(std::to_string(app_id)) != std::string::npos) { + if (entry.is_regular_file() && + std::ranges::find(extensions, entry.path().extension().string()) != extensions.end() && + entry.path().filename().string().find(std::to_string(app_id)) != std::string::npos) { return QString::fromStdString(entry.path().string()); } } @@ -586,6 +598,8 @@ void UIModel::setAcrylicEffect(bool has_acrylic_affect) emit acrylicChanged(); } +QStringList UIModel::getSteamgridOutput() const { return steamgrid_output_; } + void UIModel::onAvailFilesResponse(QNetworkReply* reply) { @@ -658,6 +672,12 @@ void UIModel::onAvailFilesResponse(QNetworkReply* reply) } } +void UIModel::onSteamGridReadReady() +{ + steamgrid_output_.push_back(QString::fromLocal8Bit(steamgrid_proc_.readAllStandardOutput())); + emit steamgridOutputChanged(); +} + void UIModel::writeTarget(const QJsonObject& json, const QString& name) const { auto path = config_path_; diff --git a/GlosSIConfig/UIModel.h b/GlosSIConfig/UIModel.h index fa4c944..b3cb982 100644 --- a/GlosSIConfig/UIModel.h +++ b/GlosSIConfig/UIModel.h @@ -17,6 +17,7 @@ limitations under the License. #include #include #include +#include #include #include @@ -37,6 +38,8 @@ class UIModel : public QObject { Q_PROPERTY(QString versionString READ getVersionString CONSTANT) Q_PROPERTY(QString newVersionName READ getNewVersionName NOTIFY newVersionAvailable) + Q_PROPERTY(QStringList steamgridOutput READ getSteamgridOutput NOTIFY steamgridOutputChanged) + public: UIModel(); @@ -65,6 +68,7 @@ class UIModel : public QObject { #endif Q_INVOKABLE QVariantList egsGamesList() const; + Q_INVOKABLE void loadSteamGridImages(); Q_INVOKABLE QString getGridImagePath(QVariant shortcut) const; [[nodiscard]] bool writeShortcutsVDF(const std::wstring& mode, const std::wstring& name, @@ -75,13 +79,17 @@ class UIModel : public QObject { [[nodiscard]] bool hasAcrylicEffect() const; void setAcrylicEffect(bool has_acrylic_affect); + QStringList getSteamgridOutput() const; + signals: void acrylicChanged(); void targetListChanged(); void newVersionAvailable(); + void steamgridOutputChanged(); public slots: void onAvailFilesResponse(QNetworkReply* reply); + void onSteamGridReadReady(); private: #ifdef _WIN32 @@ -107,6 +115,9 @@ class UIModel : public QObject { QString new_version_name_; bool notify_on_snapshots_ = false; + QProcess steamgrid_proc_; + QStringList steamgrid_output_; + std::vector shortcuts_vdf_; void writeTarget(const QJsonObject& json, const QString& name) const; diff --git a/GlosSIConfig/qml.qrc b/GlosSIConfig/qml.qrc index 64cc986..1d07c92 100644 --- a/GlosSIConfig/qml.qrc +++ b/GlosSIConfig/qml.qrc @@ -24,5 +24,6 @@ svg/settings_fill_white_24dp.svg qml/EGSSelectDialog.qml svg/add_photo_alternate_white_24dp.svg + qml/SteamGridDialog.qml diff --git a/GlosSIConfig/qml/SteamGridDialog.qml b/GlosSIConfig/qml/SteamGridDialog.qml new file mode 100644 index 0000000..e7d3b61 --- /dev/null +++ b/GlosSIConfig/qml/SteamGridDialog.qml @@ -0,0 +1,156 @@ +/* +Copyright 2021-2022 Peter Repukat - FlatspotSoftware + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + +http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Controls.Material + +Dialog { + id: gridDialog + anchors.centerIn: parent + + signal confirmed(var param) + + visible: false + modal: true + dim: true + parent: Overlay.overlay + Overlay.modal: Rectangle { + color: Qt.rgba(0,0,0,0.4) + opacity: backdropOpacity + Behavior on opacity { + NumberAnimation { + duration: 300 + } + } + } + property real backdropOpacity: 1.0 + + property bool loading: true + + + onOpened: function() { + loading = true; + uiModel.loadSteamGridImages(); + } + + onClosed: function() { + } + + enter: Transition { + NumberAnimation{target: content; property: "y"; from: parent.height; to: 16; duration: 300; easing.type: Easing.OutQuad } + NumberAnimation{target: background; property: "y"; from: parent.height; to: 0; duration: 300; easing.type: Easing.OutQuad } + NumberAnimation{target: gridDialog; property: "backdropOpacity"; from: 0; to: 1; duration: 300; easing.type: Easing.OutQuad } + } + + exit: Transition { + NumberAnimation{target: content; property: "y"; from: 16; to: parent.height; duration: 300; easing.type: Easing.InQuad } + NumberAnimation{target: background; property: "y"; from: 0; to: parent.height; duration: 300; easing.type: Easing.InQuad } + NumberAnimation{target: gridDialog; property: "backdropOpacity"; from: 1; to: 0; duration: 300; easing.type: Easing.InQuad } + } + + background: RPane { + id: background + radius: 4 + Material.elevation: 64 + bgOpacity: 0.97 + } + contentItem: Item { + id: content + implicitWidth: listview.width + implicitHeight: listview.height + titlelabel.height + 16 + 64 + clip: true + Label { + id: titlelabel + text: qsTr("Loading Grid images...") + font.pixelSize: 24 + font.bold: true + } + + BusyIndicator { + id: busyIndicator + running: visible + anchors.top: titlelabel.bottom + anchors.topMargin: 8 + anchors.horizontalCenter: parent.horizontalCenter + opacity: loading ? 1 : 0 + height: loading ? 72 : 0 + Behavior on opacity { + NumberAnimation { + duration: 350 + easing.type: Easing.InOutQuad + } + } + visible: loading + } + + ListView { + anchors.top: busyIndicator.bottom + anchors.topMargin: 16 + anchors.bottom: parent.bottom + anchors.bottomMargin: 16 + id: listview + width: window.width * 0.45 + height: window.height * 0.66 + spacing: 0 + clip: true + model: uiModel.steamgridOutput + ScrollBar.vertical: ScrollBar { + } + onCountChanged: { + listview.positionViewAtIndex(listview.count - 1, ListView.Visible) + loading = !listview.model[listview.count - 1].includes("Press enter") + } + + Behavior on opacity { + ParallelAnimation { + NumberAnimation { + duration: 350 + easing.type: Easing.InOutQuad + } + PropertyAnimation { + target: listview + property: "anchors.topMargin" + from: window.height * 0.75 + to: 16 + duration: 350 + easing.type: Easing.InOutQuad + } + } + } + + + delegate: /* Item { + width: listview.width + height: outputLabel.implicitHeight */ + + Label { + id: outputLabel + text: modelData + } + // } + } + Button { + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.bottomMargin: 2 + anchors.rightMargin: 2 + text: qsTr("Ok") + onClicked: gridDialog.close() + } + + } +} \ No newline at end of file diff --git a/GlosSIConfig/qml/UWPSelectDialog.qml b/GlosSIConfig/qml/UWPSelectDialog.qml index d450b04..3c12235 100644 --- a/GlosSIConfig/qml/UWPSelectDialog.qml +++ b/GlosSIConfig/qml/UWPSelectDialog.qml @@ -126,15 +126,6 @@ Dialog { visible: opacity == 0 ? false : true } - Button { - anchors.right: parent.right - anchors.top: listview.bottom - anchors.topMargin: 16 - anchors.rightMargin: 2 - text: qsTr("Cancel") - onClicked: dlg.close() - } - ListView { anchors.top: searchBar.bottom anchors.topMargin: 16 @@ -218,5 +209,14 @@ Dialog { } } } + + Button { + anchors.right: parent.right + anchors.bottom: parent.bottom + anchors.bottomMargin: 2 + anchors.rightMargin: 2 + text: qsTr("Cancel") + onClicked: dlg.close() + } } } \ No newline at end of file diff --git a/GlosSIConfig/qml/main.qml b/GlosSIConfig/qml/main.qml index 0126a17..7e22a54 100644 --- a/GlosSIConfig/qml/main.qml +++ b/GlosSIConfig/qml/main.qml @@ -48,6 +48,12 @@ Window { } property bool steamShortcutsChanged: false + + onSteamShortcutsChanged: function() { + shouldShowLoadGridImagesButton = uiModel.targetList.some((shortcut) => uiModel.isInSteam(shortcut)) + } + + property bool shouldShowLoadGridImagesButton: false Component.onCompleted: function() { if (!uiModel.foundSteam) { @@ -57,6 +63,7 @@ Window { if (!uiModel.steamInputXboxSupportEnabled) { steamXboxDisabledDialog.open(); } + shouldShowLoadGridImagesButton = uiModel.targetList.some((shortcut) => uiModel.isInSteam(shortcut)) } Image { @@ -370,47 +377,64 @@ Window { windowContent.editedIndex = index; } } - Column { + Row { spacing: 8 anchors.right: parent.right anchors.bottom: parent.bottom anchors.margins: 24 - RoundButton { - id: optionsBtn - width: 64 - height: 64 - text: "" - contentItem: Item { - Image { + Column { + spacing: 8 + RoundButton { + id: optionsBtn + anchors.right: parent.right + width: 64 + height: 64 + text: "" + contentItem: Item { + Image { + anchors.centerIn: parent + source: "qrc:/svg/settings_fill_white_24dp.svg" + width: 24 + height: 24 + } + } + highlighted: true + onClicked: function() { + globalConf.opacity = 1; + homeContent.opacity = 0; + } + } + RoundButton { + id: addBtn + anchors.right: parent.right + width: 64 + height: 64 + text: "+" + contentItem: Label { anchors.centerIn: parent - source: "qrc:/svg/settings_fill_white_24dp.svg" - width: 24 - height: 24 + text: addBtn.text + font.pixelSize: 32 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + elide: Text.ElideRight } - } - highlighted: true - onClicked: function() { - globalConf.opacity = 1; - homeContent.opacity = 0; + highlighted: true + onClicked: selectTypeDialog.open() } - } - RoundButton { - id: addBtn - width: 64 - height: 64 - text: "+" - contentItem: Label { - anchors.centerIn: parent - text: addBtn.text - font.pixelSize: 32 - horizontalAlignment: Text.AlignHCenter - verticalAlignment: Text.AlignVCenter - elide: Text.ElideRight + Button { + visible: shouldShowLoadGridImagesButton || steamShortcutsChanged + id: loadGridImagesBtn + text: qsTr("🖼️ Load steam grid images") + highlighted: true + onClicked: function() { + steamGridDialog.open() + } } - highlighted: true - onClicked: selectTypeDialog.open() } + } + + } Item { @@ -532,5 +556,10 @@ Window { } } } + + SteamGridDialog { + id: steamGridDialog + } + } } diff --git a/GlosSITarget/Resource.rc b/GlosSITarget/Resource.rc index ccb5d81..009c048 100644 --- a/GlosSITarget/Resource.rc +++ b/GlosSITarget/Resource.rc @@ -51,8 +51,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 0,1,0,203000008020 - PRODUCTVERSION 0,1,0,203000008020 + FILEVERSION 0,1,0,2033009290000 + PRODUCTVERSION 0,1,0,2033009290000 FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -69,12 +69,12 @@ BEGIN BEGIN VALUE "CompanyName", "Peter Repukat - FlatspotSoftware" VALUE "FileDescription", "GlosSI - SteamTarget" - VALUE "FileVersion", "0.1.0.2-3-gcea802b" + VALUE "FileVersion", "0.1.0.2-33-g929abfe" VALUE "InternalName", "GlosSITarget" VALUE "LegalCopyright", "Copyright (C) 2021-2022 Peter Repukat - FlatspotSoftware" VALUE "OriginalFilename", "GlosSITarget.exe" VALUE "ProductName", "GlosSI" - VALUE "ProductVersion", "0.1.0.2-3-gcea802b" + VALUE "ProductVersion", "0.1.0.2-33-g929abfe" END END BLOCK "VarFileInfo" diff --git a/bundle-zip.ps1 b/bundle-zip.ps1 index c6964e7..dffea33 100644 --- a/bundle-zip.ps1 +++ b/bundle-zip.ps1 @@ -18,6 +18,7 @@ Copy-Item "..\..\vc_redist.x64.exe" -Destination "." Copy-Item "..\..\LICENSE" -Destination "./LICENSE" Copy-Item "..\..\QT_License" -Destination "./QT_License" Copy-Item "..\..\THIRD_PARTY_LICENSES.txt" -Destination "./THIRD_PARTY_LICENSES.txt" +Copy-Item "..\..\steamgrid.exe" -Destination "./steamgrid.exe" Copy-Item "C:\Qt\Tools\OpenSSL\Win_x64\bin\libcrypto-1_1-x64.dll" -Destination "./libcrypto-1_1-x64.dll" Copy-Item "C:\Qt\Tools\OpenSSL\Win_x64\bin\libssl-1_1-x64.dll" -Destination "./libssl-1_1-x64.dll" diff --git a/prebuild.ps1 b/prebuild.ps1 index 23c6fff..b2ee11e 100644 --- a/prebuild.ps1 +++ b/prebuild.ps1 @@ -14,4 +14,20 @@ cd .\GlosSIConfig\ ..\version_help.ps1 -cd ../ \ No newline at end of file +$apiKeyText = " +/* Autogenerated version info file */ +#pragma once + +inline const char* steamgridb_key = ""$env:STEAMGRIDDB_KEY""; +" + +if (!(Test-Path 'steamgrid_api_keys.h')) { + New-Item -Path "." -Name "steamgrid_api_keys.h" -ItemType "file" -Value $apiKeyText +} + +cd ../ + +if (!(Test-Path 'steamgrid.exe')) { + Invoke-WebRequest -o steamgrid.zip https://github.com/boppreh/steamgrid/releases/download/v3.4.0/steamgrid_windows.zip + 7z e steamgrid.zip steamgrid.exe +}