Add ability to trim XCI files from the application context menu (#33)

This commit is contained in:
TheToid
2024-10-23 01:25:40 +10:00
committed by GitHub
parent 7e9a293dab
commit 6253fe143a
15 changed files with 915 additions and 2 deletions

View File

@@ -134,6 +134,7 @@ namespace Ryujinx.UI
[GUI] ScrolledWindow _gameTableWindow;
[GUI] Label _gpuName;
[GUI] Label _progressLabel;
[GUI] Label _progressStatusLabel;
[GUI] Label _firmwareVersionLabel;
[GUI] Gtk.ProgressBar _progressBar;
[GUI] Box _viewBox;
@@ -727,6 +728,34 @@ namespace Ryujinx.UI
});
}
public void StartProgress(string action)
{
Application.Invoke(delegate
{
_progressStatusLabel.Text = action;
_progressStatusLabel.Visible = true;
_progressBar.Fraction = 0;
});
}
public void UpdateProgress(double percentage)
{
Application.Invoke(delegate
{
_progressBar.Fraction = percentage;
});
}
public void EndProgress()
{
Application.Invoke(delegate
{
_progressStatusLabel.Text = String.Empty;
_progressStatusLabel.Visible = false;
_progressBar.Fraction = 1.0;
});
}
public void UpdateGameTable()
{
if (_updatingGameTable || _gameLoaded)

View File

@@ -667,6 +667,22 @@
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="_progressStatusLabel">
<property name="visible">False</property>
<property name="can-focus">False</property>
<property name="margin-left">10</property>
<property name="margin-right">5</property>
<property name="margin-top">2</property>
<property name="margin-bottom">2</property>
<property name="label" translatable="yes"></property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkProgressBar" id="_progressBar">
<property name="width-request">200</property>
@@ -680,7 +696,7 @@
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
<property name="position">3</property>
</packing>
</child>
</object>

View File

@@ -25,6 +25,7 @@ namespace Ryujinx.UI.Widgets
private MenuItem _openPtcDirMenuItem;
private MenuItem _openShaderCacheDirMenuItem;
private MenuItem _createShortcutMenuItem;
private MenuItem _trimXCIMenuItem;
private void InitializeComponent()
{
@@ -198,6 +199,15 @@ namespace Ryujinx.UI.Widgets
};
_createShortcutMenuItem.Activated += CreateShortcut_Clicked;
//
// _trimXCIMenuItem
//
_trimXCIMenuItem = new MenuItem("Check and Trim XCI File")
{
TooltipText = "Check and Trim XCI File to Save Disk Space."
};
_trimXCIMenuItem.Activated += TrimXCI_Clicked;
ShowComponent();
}
@@ -224,6 +234,8 @@ namespace Ryujinx.UI.Widgets
Add(_openTitleModDirMenuItem);
Add(_openTitleSdModDirMenuItem);
Add(new SeparatorMenuItem());
Add(_trimXCIMenuItem);
Add(new SeparatorMenuItem());
Add(_manageCacheMenuItem);
Add(_extractMenuItem);

View File

@@ -13,6 +13,7 @@ using LibHac.Tools.FsSystem.NcaUtils;
using Ryujinx.Common;
using Ryujinx.Common.Configuration;
using Ryujinx.Common.Logging;
using Ryujinx.Common.Utilities;
using Ryujinx.HLE.FileSystem;
using Ryujinx.HLE.HOS;
using Ryujinx.HLE.HOS.Services.Account.Acc;
@@ -75,6 +76,7 @@ namespace Ryujinx.UI.Widgets
_extractLogoMenuItem.Sensitive = hasNca;
_createShortcutMenuItem.Sensitive = !ReleaseInformation.IsFlatHubBuild;
_trimXCIMenuItem.Sensitive = _applicationData != null && Ryujinx.Common.Utilities.XCIFileTrimmer.CanTrim(_applicationData.Path, new XCIFileTrimmerLog(_parent));
PopupAtPointer(null);
}
@@ -630,5 +632,91 @@ namespace Ryujinx.UI.Widgets
byte[] appIcon = new ApplicationLibrary(_virtualFileSystem, checkLevel).GetApplicationIcon(_applicationData.Path, ConfigurationState.Instance.System.Language, _applicationData.Id);
ShortcutHelper.CreateAppShortcut(_applicationData.Path, _applicationData.Name, _applicationData.IdString, appIcon);
}
private void ProcessTrimResult(String filename, Ryujinx.Common.Utilities.XCIFileTrimmer.OperationOutcome operationOutcome)
{
string notifyUser = null;
switch (operationOutcome)
{
case Ryujinx.Common.Utilities.XCIFileTrimmer.OperationOutcome.NoTrimNecessary:
notifyUser = "XCI File does not need to be trimmed. Check logs for further details";
break;
case Ryujinx.Common.Utilities.XCIFileTrimmer.OperationOutcome.ReadOnlyFileCannotFix:
notifyUser = "XCI File is Read Only and could not be made writable. Check logs for further details";
break;
case Ryujinx.Common.Utilities.XCIFileTrimmer.OperationOutcome.FreeSpaceCheckFailed:
notifyUser = "XCI File has data in the free space area, it is not safe to trim";
break;
case Ryujinx.Common.Utilities.XCIFileTrimmer.OperationOutcome.InvalidXCIFile:
notifyUser = "XCI File contains invalid data. Check logs for further details";
break;
case Ryujinx.Common.Utilities.XCIFileTrimmer.OperationOutcome.FileIOWriteError:
notifyUser = "XCI File could not be opened for writing. Check logs for further details";
break;
case Ryujinx.Common.Utilities.XCIFileTrimmer.OperationOutcome.FileSizeChanged:
notifyUser = "XCI File has changed in size since it was scanned. Please check the file is not being written to and try again.";
break;
case Ryujinx.Common.Utilities.XCIFileTrimmer.OperationOutcome.Successful:
_parent.UpdateGameTable();
break;
}
if (notifyUser != null)
{
GtkDialog.CreateWarningDialog("Trimming of the XCI file failed", notifyUser);
}
}
private void TrimXCI_Clicked(object sender, EventArgs args)
{
if (_applicationData?.Path == null)
{
return;
}
var trimmer = new XCIFileTrimmer(_applicationData.Path, new XCIFileTrimmerLog(_parent));
if (trimmer.CanBeTrimmed)
{
var savings = (double)trimmer.DiskSpaceSavingsB / 1024.0 / 1024.0;
var currentFileSize = (double)trimmer.FileSizeB / 1024.0 / 1024.0;
var cartDataSize = (double)trimmer.DataSizeB / 1024.0 / 1024.0;
using MessageDialog confirmationDialog = GtkDialog.CreateConfirmationDialog(
$"This function will first check the empty space and then trim the XCI File to save disk space. Continue?",
$"Current File Size: {currentFileSize:n} MB\n" +
$"Game Data Size: {cartDataSize:n} MB\n" +
$"Disk Space Savings: {savings:n} MB\n"
);
if (confirmationDialog.Run() == (int)ResponseType.Yes)
{
Thread xciFileTrimmerThread = new(() =>
{
_parent.StartProgress($"Trimming file '{_applicationData.Path}");
try
{
XCIFileTrimmer.OperationOutcome operationOutcome = trimmer.Trim();
Gtk.Application.Invoke(delegate
{
ProcessTrimResult(_applicationData.Path, operationOutcome);
});
}
finally
{
_parent.EndProgress();
}
})
{
Name = "GUI.XCIFileTrimmerThread",
IsBackground = true,
};
xciFileTrimmerThread.Start();
}
}
}
}
}

View File

@@ -0,0 +1,27 @@
using Ryujinx.Common.Logging;
using System;
namespace Ryujinx.UI
{
internal class XCIFileTrimmerLog : Ryujinx.Common.Logging.XCIFileTrimmerLog
{
private readonly MainWindow _mainWindow;
public XCIFileTrimmerLog(MainWindow mainWindow)
{
_mainWindow = mainWindow;
}
public override void Progress(long current, long total, string text, bool complete)
{
if (!complete)
{
_mainWindow.UpdateProgress((double)current / (double)total);
}
else
{
_mainWindow.EndProgress();
}
}
}
}