diff --git a/MetaforceInstaller.Core/Defaults.cs b/MetaforceInstaller.Core/Defaults.cs new file mode 100644 index 0000000..ec22aad --- /dev/null +++ b/MetaforceInstaller.Core/Defaults.cs @@ -0,0 +1,7 @@ +namespace MetaforceInstaller.Core; + +public static class Defaults +{ + public static readonly string StoragePath = + Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) + Path.DirectorySeparatorChar + "MetaforceInstaller"; +} \ No newline at end of file diff --git a/MetaforceInstaller.Core/Models/InstallationData.cs b/MetaforceInstaller.Core/Models/InstallationData.cs index 855fae7..9eadeec 100644 --- a/MetaforceInstaller.Core/Models/InstallationData.cs +++ b/MetaforceInstaller.Core/Models/InstallationData.cs @@ -3,8 +3,6 @@ public class InstallationData { public Guid Id { get; set; } = Guid.NewGuid(); - public string Title { get; set; } - public string AndroidPackagePath { get; set; } - public string WindowsServerPackagePath { get; set; } - public string WindowsAdminPackagePath { get; set; } + public required string Title { get; set; } + public required InstallationParts Parts { get; set; } } \ No newline at end of file diff --git a/MetaforceInstaller.Core/Models/InstallationParts.cs b/MetaforceInstaller.Core/Models/InstallationParts.cs index e4c1555..807c902 100644 --- a/MetaforceInstaller.Core/Models/InstallationParts.cs +++ b/MetaforceInstaller.Core/Models/InstallationParts.cs @@ -1,6 +1,6 @@ namespace MetaforceInstaller.Core.Models; -public record InstallationParts +public class InstallationParts { public string? OculusClientPath { get; init; } public string? PicoClientPath { get; init; } @@ -9,4 +9,18 @@ public record InstallationParts public string? WindowsContentPath { get; init; } public string? WindowsAdminPath { get; init; } public string? WindowsServerPath { get; init; } + + public InstallationParts ExtendPaths(string prefixPath) + { + return new InstallationParts + { + OculusClientPath = OculusClientPath is null ? null : Path.Combine(prefixPath, OculusClientPath), + PicoClientPath = PicoClientPath is null ? null : Path.Combine(prefixPath, PicoClientPath), + AndroidAdminPath = AndroidAdminPath is null ? null : Path.Combine(prefixPath, AndroidAdminPath), + AndroidContentPath = AndroidContentPath is null ? null : Path.Combine(prefixPath, AndroidContentPath), + WindowsContentPath = WindowsContentPath is null ? null : Path.Combine(prefixPath, WindowsContentPath), + WindowsAdminPath = WindowsAdminPath is null ? null : Path.Combine(prefixPath, WindowsAdminPath), + WindowsServerPath = WindowsServerPath is null ? null : Path.Combine(prefixPath, WindowsServerPath) + }; + } } \ No newline at end of file diff --git a/MetaforceInstaller.Core/Services/StorageService.cs b/MetaforceInstaller.Core/Services/StorageService.cs index 7fa1601..4ab4ffa 100644 --- a/MetaforceInstaller.Core/Services/StorageService.cs +++ b/MetaforceInstaller.Core/Services/StorageService.cs @@ -10,8 +10,7 @@ public class StorageService : IStorageService public StorageService() { - var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData); - var appDirectory = Path.Combine(appData, "MetaforceInstaller"); + var appDirectory = Defaults.StoragePath; Directory.CreateDirectory(appDirectory); _storagePath = Path.Combine(appDirectory, "installations.json"); } diff --git a/MetaforceInstaller.Core/Services/ZipScrapper.cs b/MetaforceInstaller.Core/Services/ZipScrapper.cs index 8582a68..7a4496a 100644 --- a/MetaforceInstaller.Core/Services/ZipScrapper.cs +++ b/MetaforceInstaller.Core/Services/ZipScrapper.cs @@ -30,9 +30,29 @@ public class ZipScrapper // } } - public static string ExtractZip(ZipArchive archive, string outputPath) + public static string ExtractZip(ZipArchive archive, string outputPath, IProgress? progress = null) { - archive.ExtractToDirectory(outputPath); + var entries = archive.Entries.Where(e => !string.IsNullOrEmpty(e.Name)).ToList(); + var totalEntries = entries.Count; + var processedEntries = 0; + + foreach (var entry in entries) + { + var destinationPath = Path.Combine(outputPath, entry.FullName); + var destinationDir = Path.GetDirectoryName(destinationPath); + + if (!string.IsNullOrEmpty(destinationDir)) + { + Directory.CreateDirectory(destinationDir); + Console.WriteLine($"Extracting {entry.FullName} to {destinationPath}"); + } + + entry.ExtractToFile(destinationPath, overwrite: true); + + processedEntries++; + progress?.Report((double)processedEntries / totalEntries * 100); + } + return outputPath; } diff --git a/MetaforceInstaller.UI/NewInstallationDialog.axaml b/MetaforceInstaller.UI/NewInstallationDialog.axaml index 29a5f78..1208fdd 100644 --- a/MetaforceInstaller.UI/NewInstallationDialog.axaml +++ b/MetaforceInstaller.UI/NewInstallationDialog.axaml @@ -4,11 +4,13 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" d:DesignWidth="200" d:DesignHeight="400" x:Class="MetaforceInstaller.UI.NewInstallationDialog" - Title="MetaforceInstaller"> + Title="MetaforceInstaller - Add new installation" + SizeToContent="WidthAndHeight" + CanResize="False"> - + Install server Install admin @@ -19,6 +21,7 @@ + \ No newline at end of file diff --git a/MetaforceInstaller.UI/NewInstallationDialog.axaml.cs b/MetaforceInstaller.UI/NewInstallationDialog.axaml.cs index e144dd3..e592b8c 100644 --- a/MetaforceInstaller.UI/NewInstallationDialog.axaml.cs +++ b/MetaforceInstaller.UI/NewInstallationDialog.axaml.cs @@ -1,7 +1,13 @@ -using System.IO.Compression; +using System; +using System.Collections.Generic; +using System.IO; +using System.IO.Compression; +using System.Linq; +using System.Threading.Tasks; using Avalonia.Controls; using Avalonia.Interactivity; using Avalonia.Platform.Storage; +using MetaforceInstaller.Core; using MetaforceInstaller.Core.Models; using MetaforceInstaller.Core.Services; @@ -67,6 +73,21 @@ public partial class NewInstallationDialog : Window private async void OnInstallClick(object? sender, RoutedEventArgs e) { using var archive = ZipFile.OpenRead(_zipPath); + var title = TitleTextBox.Text ?? Path.GetFileNameWithoutExtension(_zipPath); + var progress = new Progress(value => { ProgressBar.Value = value; }); + await Task.Run(() => + ZipScrapper.ExtractZip(archive, Defaults.StoragePath, progress)); + InstallButton.IsEnabled = false; + var storageService = new StorageService(); + var appData = storageService.Load(); + var installationData = new InstallationData + { + Title = title, + Parts = _installationParts.ExtendPaths(Defaults.StoragePath + Path.DirectorySeparatorChar) + }; + appData.Installations.Add(installationData); + storageService.Save(appData); + Close(); } private void UpdateCheckboxes() @@ -77,6 +98,7 @@ public partial class NewInstallationDialog : Window var androidAdminCheckbox = AndroidAdminCheckbox; var vrClientCheckbox = VrClientCheckbox; + if (string.IsNullOrEmpty(_installationParts.WindowsServerPath)) { serverCheckbox.IsEnabled = false; @@ -109,6 +131,9 @@ public partial class NewInstallationDialog : Window vrClientCheckbox.IsEnabled = false; vrClientCheckbox.Content += "\nCouldn't find any VR clients"; } + + InstallButton.IsEnabled = new List + { serverCheckbox, pcAdminCheckbox, androidAdminCheckbox, vrClientCheckbox }.Any(x => x?.IsEnabled == true); } private void OnCancelClick(object? sender, RoutedEventArgs e)