diff --git a/src/nxDumpFuse.sln.DotSettings b/src/nxDumpFuse.sln.DotSettings
new file mode 100644
index 0000000..c3ce823
--- /dev/null
+++ b/src/nxDumpFuse.sln.DotSettings
@@ -0,0 +1,2 @@
+
+ True
\ No newline at end of file
diff --git a/src/nxDumpFuse/App.axaml b/src/nxDumpFuse/App.axaml
index bbfa9b7..4cf59f7 100644
--- a/src/nxDumpFuse/App.axaml
+++ b/src/nxDumpFuse/App.axaml
@@ -3,12 +3,12 @@
xmlns:local="using:nxDumpFuse"
x:Class="nxDumpFuse.App">
-
+
-
-
-
-
-
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/nxDumpFuse/DependencyInjection/DialogServiceBootstrapper.cs b/src/nxDumpFuse/DependencyInjection/DialogServiceBootstrapper.cs
index 3bce121..71f7e2c 100644
--- a/src/nxDumpFuse/DependencyInjection/DialogServiceBootstrapper.cs
+++ b/src/nxDumpFuse/DependencyInjection/DialogServiceBootstrapper.cs
@@ -1,6 +1,5 @@
using nxDumpFuse.Extensions;
using nxDumpFuse.Interfaces;
-using nxDumpFuse.Model;
using nxDumpFuse.Services;
using Splat;
diff --git a/src/nxDumpFuse/Interfaces/IDialogService.cs b/src/nxDumpFuse/Interfaces/IDialogService.cs
index e4f5d51..44c6834 100644
--- a/src/nxDumpFuse/Interfaces/IDialogService.cs
+++ b/src/nxDumpFuse/Interfaces/IDialogService.cs
@@ -1,6 +1,5 @@
using System.Threading.Tasks;
using Avalonia.Controls;
-using nxDumpFuse.ViewModels;
namespace nxDumpFuse.Interfaces
{
diff --git a/src/nxDumpFuse/Model/Enums/FuseSimpleLogType.cs b/src/nxDumpFuse/Model/Enums/FuseSimpleLogType.cs
new file mode 100644
index 0000000..72fc22b
--- /dev/null
+++ b/src/nxDumpFuse/Model/Enums/FuseSimpleLogType.cs
@@ -0,0 +1,8 @@
+namespace nxDumpFuse.Model.Enums
+{
+ public enum FuseSimpleLogType
+ {
+ Error,
+ Information
+ }
+}
diff --git a/src/nxDumpFuse/Model/Fuse.cs b/src/nxDumpFuse/Model/Fuse.cs
index 0b687d4..d6db3da 100644
--- a/src/nxDumpFuse/Model/Fuse.cs
+++ b/src/nxDumpFuse/Model/Fuse.cs
@@ -1,11 +1,11 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using nxDumpFuse.Events;
+using nxDumpFuse.Model.Enums;
namespace nxDumpFuse.Model
{
@@ -26,7 +26,6 @@ namespace nxDumpFuse.Model
}
public event EventHandlers.FuseUpdateEventHandler? FuseUpdateEvent;
-
public event EventHandlers.FuseSimpleLogEventHandler? FuseSimpleLogEvent;
protected virtual void OnFuseUpdate(FuseUpdateInfo fuseUpdateInfo)
@@ -34,6 +33,17 @@ namespace nxDumpFuse.Model
FuseUpdateEvent?.Invoke(fuseUpdateInfo);
}
+ private void Update(int part, int parts, double progress, double progressPart)
+ {
+ OnFuseUpdate(new FuseUpdateInfo
+ {
+ Part = part,
+ Parts = parts,
+ Progress = progress,
+ ProgressPart = progressPart
+ });
+ }
+
protected virtual void OnFuseSimpleLogEvent(FuseSimpleLog log)
{
FuseSimpleLogEvent?.Invoke(log);
@@ -51,92 +61,98 @@ namespace nxDumpFuse.Model
Log(FuseSimpleLogType.Error, "Input File cannot be empty");
return;
}
-
if (string.IsNullOrEmpty(_outputDir))
{
Log(FuseSimpleLogType.Error, "Output Directory cannot be empty");
return;
}
- Log(FuseSimpleLogType.Information, "Fuse Started");
- GetOutputFilePath(_inputFilePath, _outputDir);
+
+ GetOutputFilePath();
if (string.IsNullOrEmpty(_outputFilePath))
{
Log(FuseSimpleLogType.Error, "Output path was null");
return;
}
+
var inputFiles = GetInputFiles();
if (inputFiles.Length == 0)
{
Log(FuseSimpleLogType.Error, "No input files found");
return;
}
+
FuseFiles(inputFiles, _outputFilePath);
}
- private void GetOutputFilePath(string inputFilePath, string outputDir)
+ private void GetOutputFilePath()
{
- string? fileName = Path.GetFileName(inputFilePath);
+ var fileName = Path.GetFileName(_inputFilePath);
if (Path.HasExtension(fileName))
{
- string ext = Path.GetExtension(fileName).Replace(".", string.Empty);
- List split = fileName.Split(".").ToList();
+ var ext = Path.GetExtension(fileName).Replace(".", string.Empty);
+ var split = fileName.Split(".").ToList();
if (int.TryParse(ext, out _) && split.Count >= 3 && split[^2] == XciExt) // .xci.00
{
- _outputFilePath = Path.Join(outputDir, $"{string.Join("", split.Take(split.Count - 2))}.{XciExt}");
+ _outputFilePath = Path.Join(_outputDir, $"{string.Join("", split.Take(split.Count - 2))}.{XciExt}");
}
else if (int.TryParse(ext, out _) && split.Count >= 3 && split[^2] == NspExt) // .nsp.00
- _outputFilePath = Path.Join(outputDir, $"{string.Join("", split.Take(split.Count - 2))}.{NspExt}");
- else switch (ext.Substring(0, 2))
+ _outputFilePath = Path.Join(_outputDir, $"{string.Join("", split.Take(split.Count - 2))}.{NspExt}");
+ else switch (ext[..2])
{
// .xc0
case "xc" when int.TryParse(ext.Substring(ext.Length - 1, 1), out _):
- _outputFilePath = Path.Join(outputDir, $"{Path.GetFileNameWithoutExtension(fileName)}.{XciExt}");
+ _outputFilePath = Path.Join(_outputDir, $"{Path.GetFileNameWithoutExtension(fileName)}.{XciExt}");
break;
// .ns0
case "ns" when int.TryParse(ext.Substring(ext.Length - 1, 1), out _):
- _outputFilePath = Path.Join(outputDir, $"{Path.GetFileNameWithoutExtension(fileName)}.{NspExt}");
+ _outputFilePath = Path.Join(_outputDir, $"{Path.GetFileNameWithoutExtension(fileName)}.{NspExt}");
break;
}
}
else // dir/00
{
- var inputDir = new FileInfo(inputFilePath).Directory?.Name;
+ var inputDir = new FileInfo(_inputFilePath).Directory?.Name;
if (string.IsNullOrEmpty(inputDir))
{
inputDir = Path.GetPathRoot(_inputFilePath);
_outputFilePath = $"{inputDir}.{NspExt}";
return;
}
+
var inputDirSplit = inputDir.Split(".");
- _outputFilePath = Path.Join(outputDir, inputDirSplit.Length == 1
+ _outputFilePath = Path.Join(_outputDir, inputDirSplit.Length == 1
? $"{inputDir}.{NspExt}"
: $"{string.Join("", (inputDirSplit).Take(inputDirSplit.Length - 1))}.{NspExt}");
}
}
- private async void FuseFiles(string[] inputFiles, string outputFilePath)
+ private async void FuseFiles(IReadOnlyCollection inputFiles, string outputFilePath)
{
var buffer = new byte[1024 * 1024];
var count = 0;
long totalBytes = 0;
var totalFileLength = GetTotalFileSize(inputFiles);
- Log(FuseSimpleLogType.Information, $"Fusing {inputFiles.Length} parts to {outputFilePath}:{totalFileLength / 1000}kB");
+
+ Log(FuseSimpleLogType.Information, $"Fusing {inputFiles.Count} parts to {outputFilePath} ({ToMb(totalFileLength)}MB)");
+
await using var outputStream = File.Create(outputFilePath);
foreach (var inputFilePath in inputFiles)
{
if (_cts.Token.IsCancellationRequested) return;
- ++count;
- await using var inputStream = File.OpenRead(inputFilePath);
- Log(FuseSimpleLogType.Information, $"Fusing file part {count} --> {inputFilePath}/{inputStream.Length / 1000}kB");
- var fileLength = inputStream.Length;
long currentBytes = 0;
int currentBlockSize;
+ await using var inputStream = File.OpenRead(inputFilePath);
+ var fileLength = inputStream.Length;
+
+ Log(FuseSimpleLogType.Information, $"Fusing file part {++count}-> {inputFilePath} ({ToMb(fileLength)}MB)");
+
while ((currentBlockSize = inputStream.Read(buffer, 0, buffer.Length)) > 0)
{
if (_cts.Token.IsCancellationRequested) return;
+
currentBytes += currentBlockSize;
totalBytes += currentBlockSize;
@@ -149,20 +165,21 @@ namespace nxDumpFuse.Model
Log(FuseSimpleLogType.Error, e.Message);
}
- OnFuseUpdate(new FuseUpdateInfo
- {
- Part = count,
- Parts = inputFiles.Length,
- ProgressPart = currentBytes * 100.0 / fileLength,
- Progress = totalBytes * 100.0 / totalFileLength
- });
+ var progress = totalBytes * 100.0 / totalFileLength;
+ var progressPart = currentBytes * 100.0 / fileLength;
+ Update(count, inputFiles.Count, progress, progressPart);
}
}
Log(FuseSimpleLogType.Information, "Fuse Complete");
}
- private static long GetTotalFileSize(string[] inputFiles)
+ private static long ToMb(long bytes)
+ {
+ return bytes / 1000000;
+ }
+
+ private static long GetTotalFileSize(IEnumerable inputFiles)
{
long totalFileSize = 0;
inputFiles.Select(f => f).ToList().ForEach(f => totalFileSize += new FileInfo(f).Length);
@@ -179,14 +196,9 @@ namespace nxDumpFuse.Model
public void StopFuse()
{
_cts.Cancel();
+
Log(FuseSimpleLogType.Information, "Fuse Stopped");
- OnFuseUpdate(new FuseUpdateInfo
- {
- Part = 0,
- Parts = 0,
- ProgressPart = 0,
- Progress = 0
- });
+
if (File.Exists(_outputFilePath))
{
Task.Run((() =>
@@ -198,6 +210,7 @@ namespace nxDumpFuse.Model
{
File.Delete(_outputFilePath);
Avalonia.Threading.Dispatcher.UIThread.InvokeAsync(() => Log(FuseSimpleLogType.Information, $"Deleted {_outputFilePath}"));
+ Update(0, 0, 0, 0);
break;
}
catch (IOException)
diff --git a/src/nxDumpFuse/Model/FuseSimpleLog.cs b/src/nxDumpFuse/Model/FuseSimpleLog.cs
index 4b39644..8b4b576 100644
--- a/src/nxDumpFuse/Model/FuseSimpleLog.cs
+++ b/src/nxDumpFuse/Model/FuseSimpleLog.cs
@@ -1,15 +1,9 @@
using System;
-using System.Diagnostics;
using Avalonia.Media;
+using nxDumpFuse.Model.Enums;
namespace nxDumpFuse.Model
{
- public enum FuseSimpleLogType
- {
- Error,
- Information
- }
-
public class FuseSimpleLog
{
public FuseSimpleLog(FuseSimpleLogType type, DateTime time, string message)
@@ -17,8 +11,9 @@ namespace nxDumpFuse.Model
Type = type;
Time = time;
Message = message;
+ // This is not working, seems to be an issue https://github.com/AvaloniaUI/Avalonia/issues/2482
+ // needs to be reviewed. Setting Foreground property directly works fine, however binding fails
Color = Type == FuseSimpleLogType.Information ? Brushes.White : Brushes.Red;
- Debug.WriteLine($"Color is {Color}");
}
public FuseSimpleLogType Type { get; }
diff --git a/src/nxDumpFuse/Services/DialogService.cs b/src/nxDumpFuse/Services/DialogService.cs
index d9a41c6..7cfc904 100644
--- a/src/nxDumpFuse/Services/DialogService.cs
+++ b/src/nxDumpFuse/Services/DialogService.cs
@@ -1,18 +1,18 @@
using System.Threading.Tasks;
-using Avalonia;
using Avalonia.Controls;
using nxDumpFuse.Interfaces;
-using nxDumpFuse.ViewModels;
namespace nxDumpFuse.Services
{
public class DialogService : IDialogService
{
private readonly IMainWindowProvider _mainWindowProvider;
+
public DialogService(IMainWindowProvider mainWindowProvider)
{
_mainWindowProvider = mainWindowProvider;
}
+
public async Task ShowOpenFileDialogAsync(string title, FileDialogFilter filter)
{
var openFileDialog = new OpenFileDialog()
diff --git a/src/nxDumpFuse/ViewModels/AboutViewModel.cs b/src/nxDumpFuse/ViewModels/AboutViewModel.cs
index 8e6645a..a970c62 100644
--- a/src/nxDumpFuse/ViewModels/AboutViewModel.cs
+++ b/src/nxDumpFuse/ViewModels/AboutViewModel.cs
@@ -9,8 +9,7 @@ namespace nxDumpFuse.ViewModels
{
public class AboutViewModel : ViewModelBase, IAboutViewModel
{
- private string _gitHubUrl = "https://github.com/oMaN-Rod/nxDumpFuse";
- private string _explorer = "explorer.exe";
+ private const string GitHubUrl = "https://github.com/oMaN-Rod/nxDumpFuse";
public AboutViewModel()
{
@@ -20,28 +19,29 @@ namespace nxDumpFuse.ViewModels
public ReactiveCommand OpenGithubCommand { get; }
public string UsageText => BuildUsageText();
+
public string AuthorInfo => "Made for fun by oMaN-Rod, check me out on -->";
- private void OpenGithub()
+ private static void OpenGithub()
{
try
{
- Process.Start(_explorer, _gitHubUrl);
+ Process.Start("explorer.exe", GitHubUrl);
}
catch
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
- Process.Start("xdg-open", _gitHubUrl);
+ Process.Start("xdg-open", GitHubUrl);
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
{
- Process.Start("open", _gitHubUrl);
+ Process.Start("open", GitHubUrl);
}
}
}
- private string BuildUsageText()
+ private static string BuildUsageText()
{
var sb = new StringBuilder();
sb.AppendLine("To fuse files make sure all file parts are alone in a directory with no other files, i.e");
diff --git a/src/nxDumpFuse/ViewModels/FuseViewModel.cs b/src/nxDumpFuse/ViewModels/FuseViewModel.cs
index 3b1769c..3250f73 100644
--- a/src/nxDumpFuse/ViewModels/FuseViewModel.cs
+++ b/src/nxDumpFuse/ViewModels/FuseViewModel.cs
@@ -1,12 +1,11 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.Diagnostics;
using System.Reactive;
using Avalonia.Controls;
using nxDumpFuse.Interfaces;
using nxDumpFuse.Model;
-using nxDumpFuse.Services;
+using nxDumpFuse.Model.Enums;
using ReactiveUI;
namespace nxDumpFuse.ViewModels
diff --git a/src/nxDumpFuse/Views/AboutView.axaml b/src/nxDumpFuse/Views/AboutView.axaml
index 072f93b..f801152 100644
--- a/src/nxDumpFuse/Views/AboutView.axaml
+++ b/src/nxDumpFuse/Views/AboutView.axaml
@@ -2,26 +2,20 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
- xmlns:imaging="clr-namespace:Avalonia.Media.Imaging;assembly=Avalonia.Visuals"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="nxDumpFuse.Views.AboutView"
xmlns:vm="clr-namespace:nxDumpFuse.ViewModels"
x:DataType="vm:AboutViewModel">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/nxDumpFuse/Views/FuseView.axaml b/src/nxDumpFuse/Views/FuseView.axaml
index 4b1623f..3a94afa 100644
--- a/src/nxDumpFuse/Views/FuseView.axaml
+++ b/src/nxDumpFuse/Views/FuseView.axaml
@@ -5,58 +5,53 @@
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="nxDumpFuse.Views.FuseView"
xmlns:vm="clr-namespace:nxDumpFuse.ViewModels"
- x:DataType="vm:FuseViewModel"
- Name="FuseViewControl">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ x:DataType="vm:FuseViewModel">
+
+
-
-
+
+
-
-
+
+
-
-
-
-
+
+
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/nxDumpFuse/Views/MainView.axaml b/src/nxDumpFuse/Views/MainView.axaml
index ea850d3..5191156 100644
--- a/src/nxDumpFuse/Views/MainView.axaml
+++ b/src/nxDumpFuse/Views/MainView.axaml
@@ -1,35 +1,35 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/nxDumpFuse/Views/MainWindow.axaml b/src/nxDumpFuse/Views/MainWindow.axaml
index 57d04b1..7723640 100644
--- a/src/nxDumpFuse/Views/MainWindow.axaml
+++ b/src/nxDumpFuse/Views/MainWindow.axaml
@@ -1,29 +1,29 @@
-
-
-
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ xmlns:vm="clr-namespace:nxDumpFuse.ViewModels;assembly=nxDumpFuse"
+ xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+ x:Class="nxDumpFuse.Views.MainWindow"
+ x:Name="MainWindow"
+ xmlns:local="clr-namespace:nxDumpFuse.Views"
+ xmlns:nxDumpFuse="clr-namespace:nxDumpFuse"
+ Icon="{x:Null}"
+ Title="nxDumpFuse"
+ WindowStartupLocation="CenterScreen"
+ Background="{x:Null}"
+ Width="1280" Height="720">
+
+
+
-
-
-
+
+
+
-
-
-
+
+
+
\ No newline at end of file
diff --git a/src/nxDumpFuse/nxDumpFuse.csproj b/src/nxDumpFuse/nxDumpFuse.csproj
index 6dbf554..39bba19 100644
--- a/src/nxDumpFuse/nxDumpFuse.csproj
+++ b/src/nxDumpFuse/nxDumpFuse.csproj
@@ -5,8 +5,9 @@
enable
true
true
-
- osx-x64
+ win10-x64
+
+
true
nxDumpFuse.ico