GlosSIConfig: Find and launch EGS games

pull/192/head
Peter Repukat 2 years ago
parent 929abfe5f2
commit b568418891

@ -143,6 +143,7 @@
<None Include="GetAUMIDs.ps1" />
<None Include="qml\AdvancedTargetSettings.qml" />
<None Include="qml\CollapsiblePane.qml" />
<None Include="qml\EGSSelectDialog.qml" />
<None Include="qml\GlobalConf.qml" />
<None Include="qml\SteamInputXboxDisabledDialog.qml" />
<None Include="qml\AddSelectTypeDialog.qml" />

@ -80,6 +80,9 @@
<None Include="qml\GlobalConf.qml">
<Filter>qml</Filter>
</None>
<None Include="qml\EGSSelectDialog.qml">
<Filter>qml</Filter>
</None>
</ItemGroup>
<ItemGroup>
<QtMoc Include="UIModel.h">

@ -51,8 +51,8 @@ END
//
VS_VERSION_INFO VERSIONINFO
FILEVERSION 0,0,9,1037005000102
PRODUCTVERSION 0,0,9,1037005000102
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 - Config"
VALUE "FileVersion", "0.0.9.1-37-g5ebe102"
VALUE "FileVersion", "0.1.0.2-33-g929abfe"
VALUE "InternalName", "GlosSIConfig"
VALUE "LegalCopyright", "Copyright (C) 2021 Peter Repukat - FlatspotSoftware"
VALUE "OriginalFilename", "GlosSIConfig.exe"
VALUE "ProductName", "GlosSI"
VALUE "ProductVersion", "0.0.9.1-37-g5ebe102"
VALUE "ProductVersion", "0.1.0.2-33-g929abfe"
END
END
BLOCK "VarFileInfo"
@ -1092,6 +1092,166 @@ IDI_ICON1 ICON "..\GlosSI_Icon.ico"

@ -416,6 +416,31 @@ void UIModel::saveDefaultConf(QVariantMap conf) const
QVariantList UIModel::uwpApps() { return UWPFetch::UWPAppList(); }
#endif
QVariantList UIModel::egsGamesList() const
{
wchar_t* program_data_path_str;
std::filesystem::path path;
if (SHGetKnownFolderPath(FOLDERID_ProgramData, KF_FLAG_CREATE, NULL, &program_data_path_str) != S_OK) {
qDebug() << "Couldn't get ProgramDataPath";
return {{"InstallLocation", "Error"}};
}
path = std::filesystem::path(program_data_path_str);
path /= egs_games_json_path_;
QFile file(path);
if (file.open(QIODevice::ReadOnly)) {
const auto data = file.readAll();
file.close();
auto json = QJsonDocument::fromJson(data).object();
if (json["InstallationList"].isArray()) {
return json["InstallationList"].toVariant().toList();
}
qDebug() << "InstallationList does not exist!";
}
qDebug() << "Couldn't read EGS LauncherInstalled.dat " << path;
return {{"InstallLocation", "Error"}};
}
bool UIModel::writeShortcutsVDF(const std::wstring& mode, const std::wstring& name, const std::wstring& shortcutspath,
bool is_admin_try) const
{

@ -29,6 +29,7 @@ class UIModel : public QObject {
Q_PROPERTY(bool hasAcrlyicEffect READ hasAcrylicEffect NOTIFY acrylicChanged)
Q_PROPERTY(QVariantList targetList READ getTargetList NOTIFY targetListChanged)
Q_PROPERTY(QVariantList uwpList READ uwpApps CONSTANT)
Q_PROPERTY(QVariantList egsList READ egsGamesList CONSTANT)
Q_PROPERTY(bool foundSteam READ foundSteam CONSTANT)
Q_PROPERTY(bool steamInputXboxSupportEnabled READ isSteamInputXboxSupportEnabled CONSTANT)
@ -60,6 +61,7 @@ class UIModel : public QObject {
#ifdef _WIN32
Q_INVOKABLE QVariantList uwpApps();
#endif
Q_INVOKABLE QVariantList egsGamesList() const;
[[nodiscard]] bool writeShortcutsVDF(const std::wstring& mode, const std::wstring& name,
const std::wstring& shortcutspath, bool is_admin_try = false) const;
@ -92,6 +94,9 @@ class UIModel : public QObject {
QString user_data_path_ = "/userdata/";
QString steam_executable_name_ = "steam.exe";
const std::wstring_view egs_games_json_path_ =
L"Epic/UnrealEngineLauncher/LauncherInstalled.dat";
QVariantList targets_;
QString new_version_name_;

@ -22,5 +22,6 @@
<file>qml/AdvancedTargetSettings.qml</file>
<file>qml/GlobalConf.qml</file>
<file>svg/settings_fill_white_24dp.svg</file>
<file>qml/EGSSelectDialog.qml</file>
</qresource>
</RCC>

@ -89,7 +89,7 @@ Dialog {
}
}
Button {
visible: uiModel.isWindows
visible: uiModel.isWindows
text: qsTr("UWP App")
highlighted: true
onClicked: function(){
@ -97,6 +97,15 @@ Dialog {
confirmed("uwp")
}
}
Button {
visible: uiModel.isWindows
text: qsTr("EGS Game")
highlighted: true
onClicked: function(){
close()
confirmed("egs")
}
}
}
}

@ -0,0 +1,230 @@
/*
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 6.2
import QtQuick.Controls 6.2
import QtQuick.Layouts 6.2
import QtQuick.Controls.Material 6.2
Dialog {
id: dlg
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 var unfilteredModel: null;
property var filteredModel: [];
onOpened: function() {
unfilteredModel = null;
unfilteredModel = uiModel.egsList;
listview.model = null;
filteredModel = [];
for(let i = 0; i < unfilteredModel.length; i++)
{
filteredModel.push(unfilteredModel[i])
}
listview.model = filteredModel
}
onClosed: function() {
listview.model = null;
unfilteredModel = null;
filteredModel = null;
}
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: dlg; 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: dlg; 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("Select Epic Games Launcher Game...")
font.pixelSize: 24
font.bold: true
}
FluentTextInput {
width: listview.width - 2
x: 1
anchors.top: titlelabel.bottom
anchors.topMargin: 8
id: searchBar
enabled: true
placeholderText: qsTr("Search...")
text: ""
onTextChanged: function() {
listview.model = null;
filteredModel = [];
for(let i = 0; i < unfilteredModel.length; i++)
{
if(unfilteredModel[i].AppName.toLowerCase().includes(searchBar.text.toLowerCase())) {
filteredModel.push(unfilteredModel[i])
}
}
listview.model = filteredModel
}
}
BusyIndicator {
running: visible
anchors.centerIn: parent
opacity: (!unfilteredModel || unfilteredModel.length == 0) ? 1 : 0
Behavior on opacity {
NumberAnimation {
duration: 350
easing.type: Easing.InOutQuad
}
}
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
id: listview
width: window.width * 0.45
height: window.height * 0.66
spacing: 0
clip: true
model: filteredModel
ScrollBar.vertical: ScrollBar {
}
opacity: (!unfilteredModel || unfilteredModel.length == 0) ? 0 : 1
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: textcolumn.implicitHeight > 72 ? 500 : 72
/*Image {
id: maybeIcon
width: textcolumn.implicitHeight > 72 ? 0 : 56
height: 56
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
source: "file:///" + modelData.IconPath
mipmap: true
smooth: true
}*/
Column {
id: textcolumn
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: 16
anchors.verticalCenter: parent.verticalCenter
spacing: 2
Label {
text: modelData.InstallLocation.split('/').pop().split('\\').pop()
font.pixelSize: 18
font.bold: true
}
Label {
id: appNameLabel
text: "AppName: " + modelData.AppName
font.pixelSize: 12
wrapMode: Text.WordWrap
width: parent.width
}
Label {
id: fullPathLabel
text: modelData.InstallLocation
font.pixelSize: 12
color: '#888888'
wrapMode: Text.WordWrap
width: parent.width
}
}
Rectangle {
anchors.bottom: parent.bottom
height: 1
width: parent.width
color: Qt.rgba(1,1,1,0.25)
}
MouseArea {
anchors.fill: parent
onClicked: function(){
confirmed(modelData)
dlg.close();
}
}
}
}
}
}

@ -26,6 +26,7 @@ Item {
property alias fileDialog: fileDialog
property alias uwpSelectDialog: uwpSelectDialog
property alias egsSelectDialog: egsSelectDialog
signal cancel()
signal done(var shortcut)
@ -309,6 +310,21 @@ Item {
launchApp.checked = true
}
}
EGSSelectDialog {
id: egsSelectDialog
onConfirmed: function(modelData) {
if (nameInput.text == "") {
nameInput.text = modelData.InstallLocation.split('/').pop().split('\\').pop()
}
pathInput.text = "com.epicgames.launcher://apps/"
+ modelData.NamespaceId
+ "%3A"
+ modelData.ItemId
+ "%3A"
+ modelData.ArtifactId + "?action=launch&silent=true"
launchApp.checked = true
}
}
InfoDialog {
id: helpInfoDialog

@ -387,6 +387,9 @@ Window {
if (param == "uwp") {
props.uwpSelectDialog.open();
}
if (param == "egs") {
props.egsSelectDialog.open();
}
}
}
}

Loading…
Cancel
Save