mirror of
https://git.ryujinx.app/ryubing/ryujinx.git
synced 2025-07-23 06:37:10 +02:00
Add ability to trim and untrim XCI files from the application context menu AND in Bulk (#105)
This commit is contained in:
parent
47b8145809
commit
4831965404
23 changed files with 2095 additions and 3 deletions
62
src/Ryujinx/UI/Helpers/AvaloniaListExtensions.cs
Normal file
62
src/Ryujinx/UI/Helpers/AvaloniaListExtensions.cs
Normal file
|
@ -0,0 +1,62 @@
|
|||
using Avalonia.Collections;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Helpers
|
||||
{
|
||||
public static class AvaloniaListExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Adds or Replaces an item in an AvaloniaList irrespective of whether the item already exists
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the element in the AvaoloniaList</typeparam>
|
||||
/// <param name="list">The list containing the item to replace</param>
|
||||
/// <param name="item">The item to replace</param>
|
||||
/// <param name="addIfNotFound">True to add the item if its not found</param>
|
||||
/// <returns>True if the item was found and replaced, false if it was addded</returns>
|
||||
/// <remarks>
|
||||
/// The indexes on the AvaloniaList will only replace if the item does not match,
|
||||
/// this causes the items to not be replaced if the Equality is customised on the
|
||||
/// items. This method will instead find, remove and add the item to ensure it is
|
||||
/// replaced correctly.
|
||||
/// </remarks>
|
||||
public static bool ReplaceWith<T>(this AvaloniaList<T> list, T item, bool addIfNotFound = true)
|
||||
{
|
||||
var index = list.IndexOf(item);
|
||||
|
||||
if (index != -1)
|
||||
{
|
||||
list.RemoveAt(index);
|
||||
list.Insert(index, item);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(item);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds or Replaces items in an AvaloniaList from another list irrespective of whether the item already exists
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the element in the AvaoloniaList</typeparam>
|
||||
/// <param name="list">The list containing the item to replace</param>
|
||||
/// <param name="sourceList">The list of items to be actually added to `list`</param>
|
||||
/// <param name="matchingList">The items to use as matching records to search for in the `sourceList', if not found this item will be added instead</params>
|
||||
public static void AddOrReplaceMatching<T>(this AvaloniaList<T> list, IList<T> sourceList, IList<T> matchingList)
|
||||
{
|
||||
foreach (var match in matchingList)
|
||||
{
|
||||
var index = sourceList.IndexOf(match);
|
||||
if (index != -1)
|
||||
{
|
||||
list.ReplaceWith(sourceList[index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
list.ReplaceWith(match);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Data.Converters;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.UI.Common.Models;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Helpers
|
||||
{
|
||||
internal class XCITrimmerFileSpaceSavingsConverter : IValueConverter
|
||||
{
|
||||
private const long _bytesPerMB = 1024 * 1024;
|
||||
public static XCITrimmerFileSpaceSavingsConverter Instance = new();
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is UnsetValueType)
|
||||
{
|
||||
return BindingOperations.DoNothing;
|
||||
}
|
||||
|
||||
if (!targetType.IsAssignableFrom(typeof(string)))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (value is not XCITrimmerFileModel app)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (app.CurrentSavingsB < app.PotentialSavingsB)
|
||||
{
|
||||
return LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.TitleXCICanSaveLabel, (app.PotentialSavingsB - app.CurrentSavingsB) / _bytesPerMB);
|
||||
}
|
||||
else
|
||||
{
|
||||
return LocaleManager.Instance.UpdateAndGetDynamicValue(LocaleKeys.TitleXCISavingLabel, app.CurrentSavingsB / _bytesPerMB);
|
||||
}
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
46
src/Ryujinx/UI/Helpers/XCITrimmerFileStatusConverter.cs
Normal file
46
src/Ryujinx/UI/Helpers/XCITrimmerFileStatusConverter.cs
Normal file
|
@ -0,0 +1,46 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Data.Converters;
|
||||
using Ryujinx.Ava.Common.Locale;
|
||||
using Ryujinx.UI.Common.Models;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using static Ryujinx.Common.Utilities.XCIFileTrimmer;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Helpers
|
||||
{
|
||||
internal class XCITrimmerFileStatusConverter : IValueConverter
|
||||
{
|
||||
public static XCITrimmerFileStatusConverter Instance = new();
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is UnsetValueType)
|
||||
{
|
||||
return BindingOperations.DoNothing;
|
||||
}
|
||||
|
||||
if (!targetType.IsAssignableFrom(typeof(string)))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (value is not XCITrimmerFileModel app)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return app.PercentageProgress != null ? String.Empty :
|
||||
app.ProcessingOutcome != OperationOutcome.Successful && app.ProcessingOutcome != OperationOutcome.Undetermined ? LocaleManager.Instance[LocaleKeys.TitleXCIStatusFailedLabel] :
|
||||
app.Trimmable & app.Untrimmable ? LocaleManager.Instance[LocaleKeys.TitleXCIStatusPartialLabel] :
|
||||
app.Trimmable ? LocaleManager.Instance[LocaleKeys.TitleXCIStatusTrimmableLabel] :
|
||||
app.Untrimmable ? LocaleManager.Instance[LocaleKeys.TitleXCIStatusUntrimmableLabel] :
|
||||
String.Empty;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
using Avalonia;
|
||||
using Avalonia.Data;
|
||||
using Avalonia.Data.Converters;
|
||||
using Ryujinx.UI.Common.Models;
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using static Ryujinx.Common.Utilities.XCIFileTrimmer;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Helpers
|
||||
{
|
||||
internal class XCITrimmerFileStatusDetailConverter : IValueConverter
|
||||
{
|
||||
public static XCITrimmerFileStatusDetailConverter Instance = new();
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (value is UnsetValueType)
|
||||
{
|
||||
return BindingOperations.DoNothing;
|
||||
}
|
||||
|
||||
if (!targetType.IsAssignableFrom(typeof(string)))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
if (value is not XCITrimmerFileModel app)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return app.PercentageProgress != null ? null :
|
||||
app.ProcessingOutcome != OperationOutcome.Successful && app.ProcessingOutcome != OperationOutcome.Undetermined ? app.ProcessingOutcome.ToLocalisedText() :
|
||||
null;
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
}
|
||||
}
|
36
src/Ryujinx/UI/Helpers/XCITrimmerOperationOutcomeHelper.cs
Normal file
36
src/Ryujinx/UI/Helpers/XCITrimmerOperationOutcomeHelper.cs
Normal file
|
@ -0,0 +1,36 @@
|
|||
using Ryujinx.Ava.Common.Locale;
|
||||
using static Ryujinx.Common.Utilities.XCIFileTrimmer;
|
||||
|
||||
namespace Ryujinx.Ava.UI.Helpers
|
||||
{
|
||||
public static class XCIFileTrimmerOperationOutcomeExtensions
|
||||
{
|
||||
public static string ToLocalisedText(this OperationOutcome operationOutcome)
|
||||
{
|
||||
switch (operationOutcome)
|
||||
{
|
||||
case OperationOutcome.NoTrimNecessary:
|
||||
return LocaleManager.Instance[LocaleKeys.TrimXCIFileNoTrimNecessary];
|
||||
case OperationOutcome.NoUntrimPossible:
|
||||
return LocaleManager.Instance[LocaleKeys.TrimXCIFileNoUntrimPossible];
|
||||
case OperationOutcome.ReadOnlyFileCannotFix:
|
||||
return LocaleManager.Instance[LocaleKeys.TrimXCIFileReadOnlyFileCannotFix];
|
||||
case OperationOutcome.FreeSpaceCheckFailed:
|
||||
return LocaleManager.Instance[LocaleKeys.TrimXCIFileFreeSpaceCheckFailed];
|
||||
case OperationOutcome.InvalidXCIFile:
|
||||
return LocaleManager.Instance[LocaleKeys.TrimXCIFileInvalidXCIFile];
|
||||
case OperationOutcome.FileIOWriteError:
|
||||
return LocaleManager.Instance[LocaleKeys.TrimXCIFileFileIOWriteError];
|
||||
case OperationOutcome.FileSizeChanged:
|
||||
return LocaleManager.Instance[LocaleKeys.TrimXCIFileFileSizeChanged];
|
||||
case OperationOutcome.Cancelled:
|
||||
return LocaleManager.Instance[LocaleKeys.TrimXCIFileCancelled];
|
||||
case OperationOutcome.Undetermined:
|
||||
return LocaleManager.Instance[LocaleKeys.TrimXCIFileFileUndertermined];
|
||||
case OperationOutcome.Successful:
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue