diff --git a/.idea/.idea.SPTInstaller/.idea/avalonia.xml b/.idea/.idea.SPTInstaller/.idea/avalonia.xml
index c49db03..64fdacd 100644
--- a/.idea/.idea.SPTInstaller/.idea/avalonia.xml
+++ b/.idea/.idea.SPTInstaller/.idea/avalonia.xml
@@ -19,6 +19,9 @@
+
+
+
diff --git a/SPTInstaller/App.axaml b/SPTInstaller/App.axaml
index 3331a7d..795db43 100644
--- a/SPTInstaller/App.axaml
+++ b/SPTInstaller/App.axaml
@@ -48,5 +48,8 @@
+
+
\ No newline at end of file
diff --git a/SPTInstaller/Helpers/FileHelper.cs b/SPTInstaller/Helpers/FileHelper.cs
index 61681c9..786dae3 100644
--- a/SPTInstaller/Helpers/FileHelper.cs
+++ b/SPTInstaller/Helpers/FileHelper.cs
@@ -134,12 +134,19 @@ public static class FileHelper
}
}
+ ///
+ /// Check if a path is problematic
+ ///
+ /// The path the check
+ /// The check that failed
+ /// Returns true if the path is bad, otherwise false
public static bool CheckPathForProblemLocations(string path, out PathCheck failedCheck)
{
failedCheck = new();
var problemPaths = new List()
{
+ new("SteamApps", PathCheckType.EndsWith, PathCheckAction.Warn),
new("Documents", PathCheckType.EndsWith, PathCheckAction.Warn),
new("Desktop", PathCheckType.EndsWith, PathCheckAction.Deny),
new("Battlestate Games", PathCheckType.Contains, PathCheckAction.Deny),
diff --git a/SPTInstaller/ViewModels/InstallPathSelectionViewModel.cs b/SPTInstaller/ViewModels/InstallPathSelectionViewModel.cs
new file mode 100644
index 0000000..23c93c2
--- /dev/null
+++ b/SPTInstaller/ViewModels/InstallPathSelectionViewModel.cs
@@ -0,0 +1,136 @@
+using System.Linq;
+using System.Threading.Tasks;
+using Avalonia;
+using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Platform.Storage;
+using ReactiveUI;
+using SPTInstaller.Helpers;
+using SPTInstaller.Models;
+
+namespace SPTInstaller.ViewModels;
+
+public class InstallPathSelectionViewModel : ViewModelBase
+{
+ private bool _debugging = false;
+ private InternalData _data;
+
+ private string _selectedPath;
+
+ public string SelectedPath
+ {
+ get => _selectedPath;
+ set => this.RaiseAndSetIfChanged(ref _selectedPath, value);
+ }
+
+ private bool _validPath;
+ public bool ValidPath
+ {
+ get => _validPath;
+ set => this.RaiseAndSetIfChanged(ref _validPath, value);
+ }
+
+ private string _errorMessage;
+
+ public string ErrorMessage
+ {
+ get => _errorMessage;
+ set => this.RaiseAndSetIfChanged(ref _errorMessage, value);
+ }
+
+ public InstallPathSelectionViewModel(IScreen host, bool debugging) : base(host)
+ {
+ _debugging = debugging;
+ _data = ServiceHelper.Get() ?? throw new Exception("Failed to get internal data");
+ SelectedPath = Environment.CurrentDirectory;
+ ValidPath = false;
+
+ AdjustInstallPath();
+ }
+
+ public async Task SelectFolderCommand()
+ {
+ if (Application.Current.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
+ {
+ if (desktop.MainWindow == null)
+ {
+ return;
+ }
+
+ var startingFolderPath = Directory.Exists(SelectedPath) ? SelectedPath : Environment.CurrentDirectory;
+
+ var suggestedFolder = await desktop.MainWindow.StorageProvider.TryGetFolderFromPathAsync(startingFolderPath);
+
+ var selections = await desktop.MainWindow.StorageProvider.OpenFolderPickerAsync(
+ new FolderPickerOpenOptions()
+ {
+ AllowMultiple = false,
+ SuggestedStartLocation = suggestedFolder,
+ Title = "Select a folder to install SPT into"
+ });
+
+ SelectedPath = selections.First().Path.AbsolutePath.Replace("/", "\\");
+ }
+ }
+
+ public void ValidatePath()
+ {
+ if (String.IsNullOrEmpty(SelectedPath))
+ {
+ ErrorMessage = "Please provide an install path";
+ ValidPath = false;
+ return;
+ }
+
+ if (FileHelper.CheckPathForProblemLocations(SelectedPath, out var failedCheck))
+ {
+ if (failedCheck.CheckType == PathCheckType.EndsWith)
+ {
+ ErrorMessage = "This folder can be install in, but only in a subdirectory";
+ ValidPath = false;
+ return;
+ }
+
+ if (failedCheck.CheckAction == PathCheckAction.Deny)
+ {
+ ErrorMessage = $"Sorry, you cannot install in {failedCheck.Target}";
+ ValidPath = false;
+ return;
+ }
+ }
+
+ ValidPath = true;
+ }
+
+ private void AdjustInstallPath()
+ {
+ if (FileHelper.CheckPathForProblemLocations(SelectedPath, out var failedCheck))
+ {
+ switch (failedCheck.CheckType)
+ {
+ case PathCheckType.EndsWith:
+ SelectedPath = Path.Join(Environment.CurrentDirectory, "SPT");
+ break;
+
+ case PathCheckType.Contains:
+ case PathCheckType.DriveRoot:
+ SelectedPath = Path.Join(Directory.GetDirectoryRoot(Environment.CurrentDirectory), "SPT");
+ break;
+
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
+ }
+
+ public async Task NextCommand()
+ {
+ if (FileHelper.CheckPathForProblemLocations(SelectedPath, out _))
+ {
+ return;
+ }
+
+ _data.TargetInstallPath = SelectedPath;
+
+ NavigateTo(new PreChecksViewModel(HostScreen, _debugging));
+ }
+}
\ No newline at end of file
diff --git a/SPTInstaller/ViewModels/InstallerUpdateViewModel.cs b/SPTInstaller/ViewModels/InstallerUpdateViewModel.cs
new file mode 100644
index 0000000..ff53ff2
--- /dev/null
+++ b/SPTInstaller/ViewModels/InstallerUpdateViewModel.cs
@@ -0,0 +1,12 @@
+using ReactiveUI;
+
+namespace SPTInstaller.ViewModels;
+
+public class InstallerUpdateViewModel : ViewModelBase
+{
+ private bool _debugging;
+ public InstallerUpdateViewModel(IScreen Host, bool debugging) : base(Host)
+ {
+ _debugging = debugging;
+ }
+}
\ No newline at end of file
diff --git a/SPTInstaller/ViewModels/MainWindowViewModel.cs b/SPTInstaller/ViewModels/MainWindowViewModel.cs
index 908320d..40fc793 100644
--- a/SPTInstaller/ViewModels/MainWindowViewModel.cs
+++ b/SPTInstaller/ViewModels/MainWindowViewModel.cs
@@ -31,7 +31,7 @@ public class MainWindowViewModel : ReactiveObject, IActivatableViewModel, IScree
Log.Information("System Language: {iso} - {name}", uiCulture.TwoLetterISOLanguageName, uiCulture.DisplayName);
- Router.Navigate.Execute(new PreChecksViewModel(this, debugging));
+ Router.Navigate.Execute(new InstallerUpdateViewModel(this, debugging));
}
public void CloseCommand()
diff --git a/SPTInstaller/ViewModels/PreChecksViewModel.cs b/SPTInstaller/ViewModels/PreChecksViewModel.cs
index 41ba8f2..089dd3b 100644
--- a/SPTInstaller/ViewModels/PreChecksViewModel.cs
+++ b/SPTInstaller/ViewModels/PreChecksViewModel.cs
@@ -138,7 +138,6 @@ public class PreChecksViewModel : ViewModelBase
data.OriginalGamePath = PreCheckHelper.DetectOriginalGamePath();
- data.TargetInstallPath = Environment.CurrentDirectory;
InstallPath = data.TargetInstallPath;
Log.Information($"Install Path: {FileHelper.GetRedactedPath(InstallPath)}");
@@ -224,7 +223,8 @@ public class PreChecksViewModel : ViewModelBase
{
try
{
- var installerPath = Path.Join(_installPath, "SPTInstaller.exe");
+ var installerPath = Path.Join(Environment.CurrentDirectory, "SPTInstaller.exe");
+
Process.Start(new ProcessStartInfo()
{
FileName = installerPath,
@@ -302,6 +302,7 @@ public class PreChecksViewModel : ViewModelBase
var SPTReleaseInfo =
JsonConvert.DeserializeObject(File.ReadAllText(SPTReleaseInfoFile.FullName));
+
if (SPTReleaseInfo == null)
{
InstallButtonText = "Could not parse latest SPT release";
diff --git a/SPTInstaller/Views/InstallPathSelectionView.axaml b/SPTInstaller/Views/InstallPathSelectionView.axaml
new file mode 100644
index 0000000..bc46f44
--- /dev/null
+++ b/SPTInstaller/Views/InstallPathSelectionView.axaml
@@ -0,0 +1,63 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/SPTInstaller/Views/InstallPathSelectionView.axaml.cs b/SPTInstaller/Views/InstallPathSelectionView.axaml.cs
new file mode 100644
index 0000000..3364a07
--- /dev/null
+++ b/SPTInstaller/Views/InstallPathSelectionView.axaml.cs
@@ -0,0 +1,18 @@
+using Avalonia.Controls;
+using Avalonia.ReactiveUI;
+using SPTInstaller.ViewModels;
+
+namespace SPTInstaller.Views;
+
+public partial class InstallPathSelectionView : ReactiveUserControl
+{
+ public InstallPathSelectionView()
+ {
+ InitializeComponent();
+ }
+
+ private void TextBox_OnTextChanged(object? sender, TextChangedEventArgs e)
+ {
+ ViewModel?.ValidatePath();
+ }
+}
\ No newline at end of file
diff --git a/SPTInstaller/Views/InstallerUpdateView.axaml b/SPTInstaller/Views/InstallerUpdateView.axaml
new file mode 100644
index 0000000..85e1a10
--- /dev/null
+++ b/SPTInstaller/Views/InstallerUpdateView.axaml
@@ -0,0 +1,8 @@
+
+ Welcome to Avalonia!
+
diff --git a/SPTInstaller/Views/InstallerUpdateView.axaml.cs b/SPTInstaller/Views/InstallerUpdateView.axaml.cs
new file mode 100644
index 0000000..3de3504
--- /dev/null
+++ b/SPTInstaller/Views/InstallerUpdateView.axaml.cs
@@ -0,0 +1,12 @@
+using Avalonia.ReactiveUI;
+using SPTInstaller.ViewModels;
+
+namespace SPTInstaller.Views;
+
+public partial class InstallerUpdateView : ReactiveUserControl
+{
+ public InstallerUpdateView()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file