Add ability to trim XCI files from the application context menu (#33)
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
27
src/Ryujinx.Gtk3/UI/XCIFileTrimmerLog.cs
Normal file
27
src/Ryujinx.Gtk3/UI/XCIFileTrimmerLog.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user