2023-07-12 08:32:57 +02:00
using System.Collections.ObjectModel ;
2024-02-06 18:59:39 -05:00
using System.Diagnostics ;
2023-07-12 08:32:57 +02:00
using System.Threading.Tasks ;
using System.Windows.Input ;
2023-08-23 22:45:41 -04:00
using Avalonia.Threading ;
2023-08-22 10:21:52 -04:00
using DialogHostAvalonia ;
2024-04-26 09:52:41 -07:00
using Newtonsoft.Json ;
2023-07-12 08:32:57 +02:00
using ReactiveUI ;
2023-07-29 14:26:45 -04:00
using Serilog ;
2023-05-11 23:11:39 -04:00
using SPTInstaller.Controllers ;
2023-08-25 23:46:11 -04:00
using SPTInstaller.CustomControls ;
2023-08-22 10:21:52 -04:00
using SPTInstaller.CustomControls.Dialogs ;
2023-05-11 23:11:39 -04:00
using SPTInstaller.Helpers ;
using SPTInstaller.Models ;
2024-04-26 09:52:41 -07:00
using SPTInstaller.Models.ReleaseInfo ;
2023-05-11 23:11:39 -04:00
2023-07-12 08:32:57 +02:00
namespace SPTInstaller.ViewModels ;
public class PreChecksViewModel : ViewModelBase
2023-05-11 23:11:39 -04:00
{
2024-03-25 18:19:16 -04:00
private bool _hasPreCheckSelected ;
2024-05-01 10:31:55 -04:00
2024-03-25 18:19:16 -04:00
public bool HasPreCheckSelected
2024-03-25 16:12:15 -04:00
{
2024-03-25 18:19:16 -04:00
get = > _hasPreCheckSelected ;
set = > this . RaiseAndSetIfChanged ( ref _hasPreCheckSelected , value ) ;
2024-03-25 16:12:15 -04:00
}
2024-03-24 20:52:42 -04:00
2023-07-12 08:32:57 +02:00
public ObservableCollection < PreCheckBase > PreChecks { get ; set ; } = new ( ServiceHelper . GetAll < PreCheckBase > ( ) ) ;
2024-03-24 20:52:42 -04:00
public ICommand SelectPreCheckCommand { get ; set ; }
2023-07-12 08:32:57 +02:00
public ICommand StartInstallCommand { get ; set ; }
2024-05-01 10:31:55 -04:00
2024-02-06 18:59:39 -05:00
public ICommand LaunchWithDebug { get ; set ; }
2024-05-01 10:31:55 -04:00
2024-02-06 18:59:39 -05:00
private bool _debugging ;
2024-05-01 10:31:55 -04:00
2024-02-06 18:59:39 -05:00
public bool Debugging
{
get = > _debugging ;
set = > this . RaiseAndSetIfChanged ( ref _debugging , value ) ;
}
2024-05-01 10:31:55 -04:00
2023-08-03 18:02:38 -04:00
private string _installPath ;
2024-05-01 10:31:55 -04:00
2023-07-12 08:32:57 +02:00
public string InstallPath
{
get = > _installPath ;
set = > this . RaiseAndSetIfChanged ( ref _installPath , value ) ;
}
2024-05-01 10:31:55 -04:00
2023-10-18 20:39:38 -04:00
private string _installButtonText ;
2024-05-01 10:31:55 -04:00
2023-10-18 20:39:38 -04:00
public string InstallButtonText
{
get = > _installButtonText ;
set = > this . RaiseAndSetIfChanged ( ref _installButtonText , value ) ;
}
2023-07-12 09:00:00 +02:00
2023-08-03 18:02:38 -04:00
private bool _allowInstall ;
2024-05-01 10:31:55 -04:00
2023-07-30 16:15:52 -04:00
public bool AllowInstall
2023-07-12 09:00:00 +02:00
{
2023-07-12 16:39:37 +02:00
get = > _allowInstall ;
set = > this . RaiseAndSetIfChanged ( ref _allowInstall , value ) ;
2023-07-12 09:00:00 +02:00
}
2024-05-01 10:31:55 -04:00
2024-03-24 20:52:42 -04:00
private bool _allowDetailsButton = false ;
2024-05-01 10:31:55 -04:00
2023-08-03 18:02:38 -04:00
public bool AllowDetailsButton
{
get = > _allowDetailsButton ;
set = > this . RaiseAndSetIfChanged ( ref _allowDetailsButton , value ) ;
}
2024-05-01 10:31:55 -04:00
2023-08-25 23:46:11 -04:00
private string _cacheInfoText ;
2024-05-01 10:31:55 -04:00
2023-08-25 23:46:11 -04:00
public string CacheInfoText
{
get = > _cacheInfoText ;
set = > this . RaiseAndSetIfChanged ( ref _cacheInfoText , value ) ;
}
2024-05-01 10:31:55 -04:00
2023-08-25 23:46:11 -04:00
private StatusSpinner . SpinnerState _cacheCheckState ;
2024-05-01 10:31:55 -04:00
2023-08-25 23:46:11 -04:00
public StatusSpinner . SpinnerState CacheCheckState
{
get = > _cacheCheckState ;
set = > this . RaiseAndSetIfChanged ( ref _cacheCheckState , value ) ;
}
2023-10-18 20:39:38 -04:00
private StatusSpinner . SpinnerState _installButtonCheckState ;
2024-05-01 10:31:55 -04:00
2023-10-18 20:39:38 -04:00
public StatusSpinner . SpinnerState InstallButtonCheckState
{
get = > _installButtonCheckState ;
set = > this . RaiseAndSetIfChanged ( ref _installButtonCheckState , value ) ;
}
2024-05-01 10:31:55 -04:00
2023-11-09 10:32:36 -05:00
private void ReCheckRequested ( object? sender , EventArgs e )
{
Task . Run ( async ( ) = >
{
if ( sender is InstallController installer )
{
var result = await installer . RunPreChecks ( ) ;
AllowInstall = result . Succeeded ;
}
} ) ;
}
2024-05-01 10:31:55 -04:00
2024-02-06 18:59:39 -05:00
public PreChecksViewModel ( IScreen host , bool debugging ) : base ( host )
2023-07-12 08:32:57 +02:00
{
2024-02-06 18:59:39 -05:00
Debugging = debugging ;
2023-07-12 08:32:57 +02:00
var data = ServiceHelper . Get < InternalData ? > ( ) ;
var installer = ServiceHelper . Get < InstallController ? > ( ) ;
2024-05-01 10:31:55 -04:00
2023-11-09 10:32:36 -05:00
installer . RecheckRequested + = ReCheckRequested ;
2024-05-01 10:31:55 -04:00
2023-10-18 20:39:38 -04:00
InstallButtonText = "Please wait ..." ;
InstallButtonCheckState = StatusSpinner . SpinnerState . Pending ;
2024-05-01 10:31:55 -04:00
2023-07-12 08:32:57 +02:00
if ( data = = null | | installer = = null )
2023-05-11 23:11:39 -04:00
{
2024-05-01 10:31:55 -04:00
NavigateTo ( new MessageViewModel ( HostScreen ,
Result . FromError ( "Failed to get required service for prechecks" ) ) ) ;
2023-07-12 08:32:57 +02:00
return ;
}
2024-05-01 10:31:55 -04:00
2023-07-12 08:32:57 +02:00
data . OriginalGamePath = PreCheckHelper . DetectOriginalGamePath ( ) ;
2023-10-18 20:39:38 -04:00
InstallPath = data . TargetInstallPath ;
2024-05-01 10:31:55 -04:00
2023-10-18 20:39:38 -04:00
Log . Information ( $"Install Path: {FileHelper.GetRedactedPath(InstallPath)}" ) ;
2024-05-01 10:31:55 -04:00
2023-08-22 10:21:52 -04:00
#if ! TEST
2023-07-27 10:03:24 -04:00
if ( data . OriginalGamePath = = null )
{
2024-05-01 10:31:55 -04:00
NavigateTo ( new MessageViewModel ( HostScreen ,
2024-05-25 17:34:36 +01:00
Result . FromError ( "Could not find where you installed EFT.\n\nDo you own and have the game installed?" ) ) ) ;
2023-09-16 16:49:24 -04:00
return ;
2023-07-27 10:03:24 -04:00
}
2023-08-22 10:21:52 -04:00
#endif
2024-05-01 10:31:55 -04:00
2023-09-16 16:49:24 -04:00
if ( data . OriginalGamePath = = data . TargetInstallPath )
{
Log . CloseAndFlush ( ) ;
2024-05-01 10:31:55 -04:00
2024-05-21 23:07:51 +01:00
var logFiles = Directory . GetFiles ( InstallPath , "spt-installer_*.log" ) ;
2024-05-01 10:31:55 -04:00
2023-09-16 16:49:24 -04:00
// remove log file from original game path if they exist
foreach ( var file in logFiles )
{
try
{
File . Delete ( file ) ;
}
2024-05-01 10:31:55 -04:00
catch
{
}
2023-09-16 16:49:24 -04:00
}
2024-05-01 10:31:55 -04:00
NavigateTo ( new MessageViewModel ( HostScreen ,
Result . FromError (
2024-06-29 11:25:30 -04:00
"You have chosen to install in the same folder as EFT. Please choose a another folder. Refer to the install guide on where best to place the installer before running it." ) ,
2024-05-01 10:31:55 -04:00
noLog : true ) ) ;
2023-09-16 16:49:24 -04:00
return ;
}
2024-05-01 10:31:55 -04:00
2023-08-23 22:45:41 -04:00
Task . Run ( async ( ) = >
2023-07-30 16:15:52 -04:00
{
2024-05-01 10:31:55 -04:00
if ( FileHelper . CheckPathForProblemLocations ( InstallPath , out var failedCheck ) )
2023-08-22 10:21:52 -04:00
{
2024-05-01 10:31:55 -04:00
switch ( failedCheck . CheckAction )
{
case PathCheckAction . Warn :
2023-08-23 22:45:41 -04:00
{
2024-05-01 10:31:55 -04:00
await Dispatcher . UIThread . InvokeAsync ( async ( ) = >
2024-04-05 12:29:47 -04:00
{
2024-05-01 10:31:55 -04:00
Log . Warning ( "Problem path detected, confirming install path ..." ) ;
var confirmation = await DialogHost . Show ( new ConfirmationDialog (
2024-05-25 17:34:36 +01:00
$"It appears you are installing into a folder known to cause problems: {failedCheck.Target}." +
$"\nPlease consider installing SPT somewhere else to avoid issues later on." +
$"\n\nAre you sure you want to install to this path?\n{InstallPath}" ) ) ;
2024-04-05 12:29:47 -04:00
2024-05-01 10:31:55 -04:00
if ( confirmation = = null | | ! bool . TryParse ( confirmation . ToString ( ) , out var confirm ) | |
! confirm )
{
2024-06-29 11:05:35 -04:00
Log . Information ( "User declined install path" ) ;
NavigateBack ( ) ;
2024-05-01 10:31:55 -04:00
}
} ) ;
2024-04-05 12:29:47 -04:00
2024-05-01 10:31:55 -04:00
break ;
2023-08-23 22:45:41 -04:00
}
2024-05-01 10:31:55 -04:00
case PathCheckAction . Deny :
{
Log . Error ( "Problem path detected, install denied" ) ;
NavigateTo ( new MessageViewModel ( HostScreen ,
Result . FromError (
2024-06-29 11:25:30 -04:00
$"We suspect you may be installing into a problematic folder: {failedCheck.Target}.\nWe won't be letting you install here. How did you do this?" ) ) ) ;
2024-05-01 10:31:55 -04:00
break ;
}
default :
throw new ArgumentOutOfRangeException ( ) ;
}
2023-08-23 22:45:41 -04:00
Log . Information ( "User accepted install path" ) ;
2023-08-22 10:21:52 -04:00
}
2023-08-23 22:45:41 -04:00
} ) ;
2024-05-01 10:31:55 -04:00
2024-02-06 18:59:39 -05:00
LaunchWithDebug = ReactiveCommand . Create ( async ( ) = >
{
try
{
2024-06-28 21:35:27 -04:00
var installerPath = Path . Join ( Environment . CurrentDirectory , "SPTInstaller.exe" ) ;
2024-02-06 18:59:39 -05:00
Process . Start ( new ProcessStartInfo ( )
{
FileName = installerPath ,
Arguments = "debug"
} ) ;
2024-05-01 10:31:55 -04:00
2024-02-06 18:59:39 -05:00
Environment . Exit ( 0 ) ;
}
catch ( Exception ex )
{
Log . Error ( ex , "Failed to enter debug mode" ) ;
}
} ) ;
2024-05-01 10:31:55 -04:00
SelectPreCheckCommand = ReactiveCommand . Create ( async ( PreCheckBase check ) = >
2023-08-23 22:45:41 -04:00
{
2024-03-24 20:52:42 -04:00
foreach ( var precheck in PreChecks )
{
if ( check . Id = = precheck . Id )
{
precheck . IsSelected = true ;
2024-05-01 10:31:55 -04:00
2024-03-25 18:19:16 -04:00
HasPreCheckSelected = true ;
2024-03-24 20:52:42 -04:00
continue ;
}
2024-05-01 10:31:55 -04:00
2024-03-24 20:52:42 -04:00
precheck . IsSelected = false ;
}
2023-07-30 16:15:52 -04:00
} ) ;
2024-05-01 10:31:55 -04:00
2024-03-24 20:52:42 -04:00
StartInstallCommand = ReactiveCommand . Create ( async ( ) = >
2023-07-29 14:26:45 -04:00
{
2024-03-24 20:52:42 -04:00
NavigateTo ( new InstallViewModel ( HostScreen ) ) ;
2023-07-29 14:26:45 -04:00
} ) ;
2024-05-01 10:31:55 -04:00
2023-07-12 08:32:57 +02:00
Task . Run ( async ( ) = >
{
2023-10-18 20:39:38 -04:00
// run prechecks
2023-07-12 08:32:57 +02:00
var result = await installer . RunPreChecks ( ) ;
2024-05-01 10:31:55 -04:00
2023-10-18 20:39:38 -04:00
// get latest spt version
InstallButtonText = "Getting latest release ..." ;
InstallButtonCheckState = StatusSpinner . SpinnerState . Running ;
2024-05-01 10:31:55 -04:00
2024-04-26 09:52:41 -07:00
var progress = new Progress < double > ( ( d ) = > { } ) ;
2024-05-04 16:18:49 -04:00
2024-05-21 23:07:51 +01:00
var SPTReleaseInfoFile =
2024-05-04 16:18:49 -04:00
await DownloadCacheHelper . GetOrDownloadFileAsync ( "release.json" , DownloadCacheHelper . ReleaseMirrorUrl ,
progress , DownloadCacheHelper . SuggestedTtl ) ;
2024-05-21 23:07:51 +01:00
if ( SPTReleaseInfoFile = = null )
2023-10-18 20:39:38 -04:00
{
2024-04-26 09:52:41 -07:00
InstallButtonText = "Could not get SPT release metadata" ;
2023-10-18 20:39:38 -04:00
InstallButtonCheckState = StatusSpinner . SpinnerState . Error ;
return ;
}
2024-05-01 10:31:55 -04:00
2024-05-21 23:07:51 +01:00
var SPTReleaseInfo =
JsonConvert . DeserializeObject < ReleaseInfo > ( File . ReadAllText ( SPTReleaseInfoFile . FullName ) ) ;
2024-06-28 21:35:27 -04:00
2024-05-21 23:07:51 +01:00
if ( SPTReleaseInfo = = null )
2023-10-18 20:39:38 -04:00
{
2024-04-26 09:52:41 -07:00
InstallButtonText = "Could not parse latest SPT release" ;
2023-10-18 20:39:38 -04:00
InstallButtonCheckState = StatusSpinner . SpinnerState . Error ;
return ;
}
2024-05-01 10:31:55 -04:00
2024-05-21 23:07:51 +01:00
InstallButtonText = $"Start Install: SPT v{SPTReleaseInfo.SPTVersion}" ;
2023-10-18 20:39:38 -04:00
InstallButtonCheckState = StatusSpinner . SpinnerState . OK ;
2023-08-03 18:02:38 -04:00
AllowDetailsButton = true ;
2023-07-12 16:39:37 +02:00
AllowInstall = result . Succeeded ;
2023-07-12 08:32:57 +02:00
} ) ;
2024-05-01 10:31:55 -04:00
2023-08-25 23:46:11 -04:00
Task . Run ( ( ) = >
{
CacheInfoText = "Getting cache size ..." ;
CacheCheckState = StatusSpinner . SpinnerState . Running ;
2024-05-01 10:31:55 -04:00
2023-08-25 23:46:11 -04:00
CacheInfoText = $"Cache Size: {DownloadCacheHelper.GetCacheSizeText()}" ;
CacheCheckState = StatusSpinner . SpinnerState . OK ;
} ) ;
2023-05-11 23:11:39 -04:00
}
2023-07-12 08:32:57 +02:00
}