1.0.1
Refactor, make safer, add some logging
This commit is contained in:
parent
b6181e174b
commit
4663bbca87
@ -2,7 +2,6 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
x:Class="VaultSmpInstaller.App"
|
||||
x:DataType="viewModels:ThemeViewModel"
|
||||
xmlns:local="using:VaultSmpInstaller"
|
||||
xmlns:viewModels="clr-namespace:VaultSmpInstaller.ViewModels"
|
||||
RequestedThemeVariant="Dark">
|
||||
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
|
||||
@ -17,7 +16,7 @@
|
||||
<Setter Property="Button.HorizontalAlignment" Value="Center" />
|
||||
</Style>
|
||||
<Style Selector="Button">
|
||||
<Setter Property="Button.Background" Value="{Binding ButtonBackground}"/>
|
||||
<Setter Property="Background" Value="{Binding ButtonBackground}"/>
|
||||
</Style>
|
||||
|
||||
</Application.Styles>
|
||||
|
||||
@ -6,7 +6,7 @@ using VaultSmpInstaller.Views;
|
||||
|
||||
namespace VaultSmpInstaller;
|
||||
|
||||
public partial class App : Application
|
||||
public class App : Application
|
||||
{
|
||||
public override void Initialize()
|
||||
{
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
|
||||
namespace VaultSmpInstaller.Data;
|
||||
|
||||
|
||||
@ -10,7 +10,4 @@ namespace VaultSmpInstaller.Data;
|
||||
[JsonSerializable(typeof(bool))]
|
||||
[JsonSerializable(typeof(Dictionary<string, string>))]
|
||||
[JsonSerializable(typeof(Dictionary<string, ModProfile>))]
|
||||
public partial class JsonContext: JsonSerializerContext
|
||||
{
|
||||
|
||||
}
|
||||
public partial class JsonContext: JsonSerializerContext;
|
||||
@ -1,11 +1,9 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Serialization;
|
||||
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
|
||||
|
||||
namespace VaultSmpInstaller.Data;
|
||||
|
||||
[JsonSerializable(typeof(ModProfile))]
|
||||
public class ModProfile
|
||||
{
|
||||
[JsonPropertyName("required")]
|
||||
|
||||
@ -1,11 +0,0 @@
|
||||
using Avalonia.Media;
|
||||
|
||||
namespace VaultSmpInstaller.ViewModels;
|
||||
|
||||
public class DownloadingWindowViewModel : ViewModelBase
|
||||
{
|
||||
public static Brush Background => SolidColorBrush.Parse("#282A36");
|
||||
public static Brush SecondaryBackground => SolidColorBrush.Parse("#44475A");
|
||||
public static Brush ButtonBackground => SolidColorBrush.Parse("#6272A4");
|
||||
public static Brush TextColor => SolidColorBrush.Parse("#F8F8F2");
|
||||
}
|
||||
@ -1,15 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Reactive.Linq;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Input;
|
||||
using Avalonia.Media;
|
||||
using ReactiveUI;
|
||||
@ -17,7 +10,7 @@ using VaultSmpInstaller.Data;
|
||||
|
||||
namespace VaultSmpInstaller.ViewModels;
|
||||
|
||||
public class MainWindowViewModel : ViewModelBase
|
||||
public class MainWindowViewModel : ReactiveObject
|
||||
{
|
||||
public static Brush Background => SolidColorBrush.Parse("#282A36");
|
||||
public static Brush SecondaryBackground => SolidColorBrush.Parse("#44475A");
|
||||
@ -46,7 +39,7 @@ public class MainWindowViewModel : ViewModelBase
|
||||
if (File.Exists(Path.Combine(SelectedInstance.InstancePath, "installedInstance.json")))
|
||||
{
|
||||
await using FileStream fs = new FileStream(Path.Combine(SelectedInstance.InstancePath, "installedInstance.json"), FileMode.Open);
|
||||
InstalledInstanceConfig = await JsonSerializer.DeserializeAsync<InstanceConfig>(fs, JsonContext.Default.InstanceConfig);
|
||||
InstalledInstanceConfig = await JsonSerializer.DeserializeAsync(fs, JsonContext.Default.InstanceConfig);
|
||||
if (InstalledInstanceConfig != null)
|
||||
{
|
||||
InstalledInstanceConfig.InstancePath = SelectedInstance.InstancePath;
|
||||
@ -66,8 +59,8 @@ public class MainWindowViewModel : ViewModelBase
|
||||
});
|
||||
}
|
||||
|
||||
public InstanceConfig? InstalledInstanceConfig { get; set; } = null;
|
||||
public InstanceConfig? LatestInstanceConfig { get; set; } = null;
|
||||
public InstanceConfig? InstalledInstanceConfig { get; set; }
|
||||
public InstanceConfig? LatestInstanceConfig { get; set; }
|
||||
|
||||
public Dictionary<string, ModProfile> EnabledModProfiles => LatestInstanceConfig?.ModProfiles.Where(pair => pair.Value.IsEnabled).ToDictionary() ?? new Dictionary<string, ModProfile>();
|
||||
public List<string> EnabledModProfileNames => EnabledModProfiles.Keys.ToList();
|
||||
@ -75,7 +68,7 @@ public class MainWindowViewModel : ViewModelBase
|
||||
public List<string> DisabledModProfileNames => DisabledModProfiles.Keys.ToList();
|
||||
|
||||
public Dictionary<string, ModProfile> InstalledModProfiles => InstalledInstanceConfig?.ModProfiles.Where(pair => pair.Value.IsEnabled).ToDictionary() ?? new Dictionary<string, ModProfile>();
|
||||
public List<string> InstalledModProfileNames => InstalledModProfiles.Keys.ToList();
|
||||
public List<string> InstalledModProfileNames => InstalledModProfiles.Keys.ToList();
|
||||
|
||||
public string SelectedInstanceName => SelectedInstance == null ? "No profile selected" : $"Selected Profile: {SelectedInstance.InstanceName}";
|
||||
public ProfileWindow2ViewModel.InstanceInfo? SelectedInstance { get; set; }
|
||||
|
||||
@ -9,7 +9,7 @@ using ReactiveUI;
|
||||
|
||||
namespace VaultSmpInstaller.ViewModels;
|
||||
|
||||
public class ProfileWindow1ViewModel : ViewModelBase
|
||||
public class ProfileWindow1ViewModel : ReactiveObject
|
||||
{
|
||||
public Interaction<ProfileWindow2ViewModel, ProfileWindow2ViewModel.InstanceInfo?> ShowProfileSelectionDialog { get; }
|
||||
|
||||
@ -25,12 +25,15 @@ public class ProfileWindow1ViewModel : ViewModelBase
|
||||
|
||||
UseCurseforgeCommand = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
if (curseforgeDir == null) return null;
|
||||
var profileWindowModel = new ProfileWindow2ViewModel(ProfileWindow2ViewModel.InstanceType.Curseforge, curseforgeDir);
|
||||
return await ShowProfileSelectionDialog.Handle(profileWindowModel);
|
||||
|
||||
});
|
||||
|
||||
UsePrismCommand = ReactiveCommand.CreateFromTask(async () =>
|
||||
{
|
||||
if (prismDir == null) return null;
|
||||
var profileWindowModel = new ProfileWindow2ViewModel(ProfileWindow2ViewModel.InstanceType.Prism, prismDir);
|
||||
return await ShowProfileSelectionDialog.Handle(profileWindowModel);
|
||||
});
|
||||
@ -41,8 +44,8 @@ public class ProfileWindow1ViewModel : ViewModelBase
|
||||
public static Brush ButtonBackground => SolidColorBrush.Parse("#6272A4");
|
||||
public static Brush TextColor => SolidColorBrush.Parse("#F8F8F2");
|
||||
|
||||
private string? _curseforgeInstanceDir = null;
|
||||
public bool IsCurseforgeInstalled { get; set; } = false;
|
||||
private string? _curseforgeInstanceDir;
|
||||
public bool IsCurseforgeInstalled { get; set; }
|
||||
|
||||
public string CurseforgeButtonText => IsCurseforgeInstalled ? "Curseforge" : "Curseforge Not Detected";
|
||||
|
||||
@ -61,9 +64,9 @@ public class ProfileWindow1ViewModel : ViewModelBase
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsPrismInstalled { get; set; } = false;
|
||||
public bool IsPrismInstalled { get; set; }
|
||||
|
||||
private string? _prismInstanceDir = null;
|
||||
private string? _prismInstanceDir;
|
||||
public string PrismButtonText => IsPrismInstalled ? "Prism Launcher" : "Prism Launcher Not Detected";
|
||||
|
||||
public string? PrismInstanceDir
|
||||
@ -81,7 +84,7 @@ public class ProfileWindow1ViewModel : ViewModelBase
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsOverwolfInstalled { get; set; } = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Overwolf", "UninstallString", null) != null;
|
||||
public bool IsOverwolfInstalled { get; } = Registry.GetValue(@"HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Overwolf", "UninstallString", null) != null;
|
||||
|
||||
public bool TryGetCurseforgeMinecraftRoot(out string? minecraftRoot)
|
||||
{
|
||||
@ -91,7 +94,12 @@ public class ProfileWindow1ViewModel : ViewModelBase
|
||||
|
||||
if (!File.Exists(Path.Combine(appData, "Curseforge", "storage.json"))) return false;
|
||||
|
||||
var curseforgeConfig = JsonNode.Parse(File.ReadAllText(Path.Combine(appData, "Curseforge", "storage.json")))!.AsObject();
|
||||
var curseforgeConfig = JsonNode.Parse(File.ReadAllText(Path.Combine(appData, "Curseforge", "storage.json")))?.AsObject();
|
||||
if (curseforgeConfig == null)
|
||||
{
|
||||
File.AppendAllText(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "smpinstaller.log"), "Failed to read curseforge config!\n");
|
||||
return false;
|
||||
}
|
||||
if (!curseforgeConfig.TryGetPropertyValue("minecraft-settings", out var minecraftSettingsNode))
|
||||
{
|
||||
minecraftRoot = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "curseforge", "minecraft", "Instances");
|
||||
@ -132,61 +140,4 @@ public class ProfileWindow1ViewModel : ViewModelBase
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// public bool TryGetOverwolfMinecraftRoot(out string? minecraftRoot)
|
||||
// {
|
||||
// minecraftRoot = null;
|
||||
//
|
||||
// var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
// var overwolfDbDirectory = Path.Combine(localAppData, "Overwolf", "BrowserCache", "Local Storage", "leveldb");
|
||||
//
|
||||
// if (!Directory.Exists(overwolfDbDirectory)) return false;
|
||||
//
|
||||
// var overwolfDb = new Database(new(overwolfDbDirectory), false, new Options() { ReadOnly = true});
|
||||
// byte[] databaseKey = new byte[]
|
||||
// {
|
||||
// 0x5F, 0x6F,
|
||||
// 0x76, 0x65, 0x72, 0x77, 0x6F, 0x6C, 0x66, 0x2D,
|
||||
// 0x65, 0x78, 0x74, 0x65, 0x6E, 0x73, 0x69, 0x6F,
|
||||
// 0x6E, 0x3A, 0x2F, 0x2F, 0x63, 0x63, 0x68, 0x68,
|
||||
// 0x63, 0x61, 0x69, 0x61, 0x70, 0x65, 0x69, 0x6B,
|
||||
// 0x6A, 0x62, 0x64, 0x62, 0x70, 0x66, 0x70, 0x6C,
|
||||
// 0x67, 0x6D, 0x70, 0x6F, 0x62, 0x62, 0x63, 0x64,
|
||||
// 0x6B, 0x64, 0x61, 0x70, 0x68, 0x63, 0x6C, 0x62,
|
||||
// 0x6D, 0x6B, 0x62, 0x6A, 0x00, 0x01, 0x6D, 0x69,
|
||||
// 0x6E, 0x65, 0x63, 0x72, 0x61, 0x66, 0x74, 0x2D,
|
||||
// 0x73, 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x73
|
||||
// };
|
||||
// String? curseforgeMinecraftSettings = "";
|
||||
// try
|
||||
// {
|
||||
// overwolfDb.Open();
|
||||
// curseforgeMinecraftSettings = Encoding.ASCII.GetString(overwolfDb.Get(databaseKey))[1..];
|
||||
// }
|
||||
// catch (NullReferenceException e)
|
||||
// {
|
||||
// minecraftRoot = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "curseforge", "minecraft", "Instances");
|
||||
// return true;
|
||||
// }
|
||||
// finally
|
||||
// {
|
||||
// overwolfDb.Close();
|
||||
// overwolfDb.Dispose();
|
||||
// }
|
||||
// if(String.IsNullOrEmpty(curseforgeMinecraftSettings))
|
||||
// {
|
||||
// minecraftRoot = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "curseforge", "minecraft", "Instances");
|
||||
// return true;
|
||||
// }
|
||||
//
|
||||
// var minecraftSettings = JsonNode.Parse(curseforgeMinecraftSettings);
|
||||
// if (!minecraftSettings!.AsObject().TryGetPropertyValue("minecraftRoot", out var minecraftRootNode)) {
|
||||
// minecraftRoot = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "curseforge", "minecraft", "Instances");
|
||||
// return true;
|
||||
// }
|
||||
// if (!minecraftRootNode!.AsValue().TryGetValue(out minecraftRoot)) return false;
|
||||
//
|
||||
// minecraftRoot = Path.Combine(minecraftRoot, "Instances");
|
||||
// return true;
|
||||
// }
|
||||
}
|
||||
@ -10,11 +10,10 @@ using ReactiveUI;
|
||||
|
||||
namespace VaultSmpInstaller.ViewModels;
|
||||
|
||||
public class ProfileWindow2ViewModel : ViewModelBase
|
||||
public class ProfileWindow2ViewModel : ReactiveObject
|
||||
{
|
||||
|
||||
public Interaction<ProfileWindow2ViewModel, ProfileWindow2ViewModel.InstanceInfo?> ShowProfileSelectionDialog { get; }
|
||||
public ReactiveCommand<Unit, ProfileWindow2ViewModel.InstanceInfo?> SelectProfileCommand { get; }
|
||||
public ReactiveCommand<Unit, InstanceInfo?> SelectProfileCommand { get; }
|
||||
|
||||
public static Brush Background => SolidColorBrush.Parse("#282A36");
|
||||
public static Brush SecondaryBackground => SolidColorBrush.Parse("#44475A");
|
||||
@ -37,6 +36,7 @@ public class ProfileWindow2ViewModel : ViewModelBase
|
||||
foreach (var directory in Directory.EnumerateDirectories(instancesDir))
|
||||
{
|
||||
if (!File.Exists(Path.Combine(directory, "instance.cfg"))) continue;
|
||||
|
||||
foreach(String line in File.ReadLines(Path.Combine(directory, "instance.cfg")))
|
||||
{
|
||||
if (line.StartsWith("name"))
|
||||
@ -56,12 +56,17 @@ public class ProfileWindow2ViewModel : ViewModelBase
|
||||
}
|
||||
}
|
||||
break;
|
||||
case InstanceType.Curseforge: case InstanceType.Overwolf:
|
||||
case InstanceType.Curseforge:
|
||||
foreach (var directory in Directory.EnumerateDirectories(instancesDir))
|
||||
{
|
||||
if (!File.Exists(Path.Combine(directory, "minecraftinstance.json"))) continue;
|
||||
string? instanceConfigName = null;
|
||||
if (File.Exists(Path.Combine(directory, "minecraftinstance.json"))) instanceConfigName = "minecraftinstance.json";
|
||||
if (File.Exists(Path.Combine(directory, "minecraftInstance.json"))) instanceConfigName = "minecraftInstance.json";
|
||||
|
||||
if (instanceConfigName == null) continue;
|
||||
|
||||
var instanceConfig = JsonNode.Parse(File.ReadAllText(Path.Combine(directory, "minecraftinstance.json")))!.AsObject();
|
||||
var instanceConfig = JsonNode.Parse(File.ReadAllText(Path.Combine(directory, instanceConfigName)))?.AsObject();
|
||||
if(instanceConfig == null) continue;
|
||||
if (!instanceConfig.TryGetPropertyValue("name", out var nameNode)) continue;
|
||||
if (!nameNode!.AsValue().TryGetValue(out string? instanceName)) continue;
|
||||
|
||||
@ -88,7 +93,7 @@ public class ProfileWindow2ViewModel : ViewModelBase
|
||||
|
||||
public enum InstanceType
|
||||
{
|
||||
Prism, Curseforge, Overwolf
|
||||
Prism, Curseforge
|
||||
}
|
||||
|
||||
public record InstanceInfo(String InstanceName, String InstancePath, String MinecraftPath, String ModsPath, String ConfigPath, String ScriptsPath);
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
using Avalonia.Media;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace VaultSmpInstaller.ViewModels;
|
||||
|
||||
public class ThemeViewModel : ViewModelBase
|
||||
public class ThemeViewModel : ReactiveObject
|
||||
{
|
||||
public static Brush Background => SolidColorBrush.Parse("#282A36");
|
||||
public static Brush SecondaryBackground => SolidColorBrush.Parse("#44475A");
|
||||
|
||||
@ -1,7 +0,0 @@
|
||||
using ReactiveUI;
|
||||
|
||||
namespace VaultSmpInstaller.ViewModels;
|
||||
|
||||
public class ViewModelBase : ReactiveObject
|
||||
{
|
||||
}
|
||||
@ -6,14 +6,14 @@
|
||||
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia.ProgressRing"
|
||||
mc:Ignorable="d" d:DesignWidth="300" d:DesignHeight="160"
|
||||
x:Class="VaultSmpInstaller.Views.DownloadingWindow"
|
||||
x:DataType="vm:DownloadingWindowViewModel"
|
||||
x:DataType="vm:ThemeViewModel"
|
||||
Icon="/Assets/icon.ico"
|
||||
Title="Downloading Update"
|
||||
Width="300" Height="160"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
CanResize="False">
|
||||
<Design.DataContext>
|
||||
<vm:DownloadingWindowViewModel/>
|
||||
<vm:ThemeViewModel/>
|
||||
</Design.DataContext>
|
||||
<StackPanel Background="{Binding Background}">
|
||||
<TextBlock FontSize="18" Margin="10, 10, 10, 0">Downloading Latest Release</TextBlock>
|
||||
|
||||
@ -1,6 +1,4 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Controls;
|
||||
|
||||
namespace VaultSmpInstaller.Views;
|
||||
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace VaultSmpInstaller.Views;
|
||||
|
||||
public partial class InstanceNotIntactWindow : Window
|
||||
{
|
||||
private readonly MainWindow _mainWindow;
|
||||
public InstanceNotIntactWindow() { }
|
||||
|
||||
private readonly MainWindow? _mainWindow;
|
||||
public InstanceNotIntactWindow(MainWindow mainWindow)
|
||||
{
|
||||
InitializeComponent();
|
||||
@ -18,12 +18,12 @@ public partial class InstanceNotIntactWindow : Window
|
||||
private void Continue(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(Close);
|
||||
_mainWindow.ContinueInstalling.Set();
|
||||
_mainWindow?.ContinueInstalling.Set();
|
||||
}
|
||||
|
||||
private void Cancel(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
Dispatcher.UIThread.Invoke(Close);
|
||||
Dispatcher.UIThread.Invoke(_mainWindow.Close);
|
||||
if (_mainWindow != null) Dispatcher.UIThread.Invoke(_mainWindow.Close);
|
||||
}
|
||||
}
|
||||
@ -30,7 +30,7 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
||||
private async Task ProcessInstance(String instancePath)
|
||||
{
|
||||
await using FileStream fs = new FileStream(Path.Combine(instancePath, "instance.json"), FileMode.Open);
|
||||
ViewModel!.LatestInstanceConfig = await JsonSerializer.DeserializeAsync<InstanceConfig>(fs, JsonContext.Default.InstanceConfig);
|
||||
ViewModel!.LatestInstanceConfig = await JsonSerializer.DeserializeAsync(fs, JsonContext.Default.InstanceConfig);
|
||||
if (ViewModel!.LatestInstanceConfig != null)
|
||||
{
|
||||
ViewModel!.LatestInstanceConfig.InstancePath = instancePath;
|
||||
@ -68,20 +68,19 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
||||
|
||||
private void StartDownload()
|
||||
{
|
||||
var downloadThread = new Thread(async (arg) =>
|
||||
var downloadThread = new Thread((arg) =>
|
||||
{
|
||||
if (arg is CancellationTokenSource)
|
||||
if (arg is CancellationTokenSource tokenSource)
|
||||
{
|
||||
var tokenSource = (CancellationTokenSource)arg;
|
||||
var archivePath = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".zip");
|
||||
var extractPath = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString());
|
||||
try
|
||||
{
|
||||
HttpClient httpClient = new HttpClient();
|
||||
|
||||
using var response = await httpClient.GetAsync("https://holenode.cdnbcn.net/LatestProfile.zip", tokenSource.Token);
|
||||
await using var fs = new FileStream(archivePath, FileMode.OpenOrCreate);
|
||||
await response.Content.CopyToAsync(fs, tokenSource.Token);
|
||||
using var response = httpClient.GetAsync("https://holenode.cdnbcn.net/LatestProfile.zip", tokenSource.Token).Result;
|
||||
using var fs = new FileStream(archivePath, FileMode.OpenOrCreate);
|
||||
response.Content.CopyTo(fs, null, tokenSource.Token);
|
||||
|
||||
fs.Close();
|
||||
|
||||
@ -91,16 +90,16 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
||||
|
||||
File.Delete(archivePath);
|
||||
|
||||
await Dispatcher.UIThread.Invoke(() => ProcessInstance(extractPath));
|
||||
Dispatcher.UIThread.Invoke(() => ProcessInstance(extractPath));
|
||||
}
|
||||
catch (OperationCanceledException e)
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
try
|
||||
{
|
||||
File.Delete(archivePath);
|
||||
Directory.Delete(extractPath, true);
|
||||
}
|
||||
catch (Exception ignored)
|
||||
catch (Exception)
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
@ -112,7 +111,7 @@ public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
|
||||
|
||||
CancellationTokenSource source = new CancellationTokenSource();
|
||||
downloadThread.Start(source);
|
||||
_downloadingWindow.DataContext = new DownloadingWindowViewModel();
|
||||
_downloadingWindow.DataContext = new ThemeViewModel();
|
||||
_downloadingWindow.Closed += (_, _) => source.Cancel();
|
||||
_downloadingWindow.ShowDialog(this);
|
||||
}
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
using System;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
using ReactiveUI;
|
||||
using VaultSmpInstaller.ViewModels;
|
||||
@ -17,9 +15,9 @@ public partial class ProfileWindow2 : ReactiveWindow<ProfileWindow2ViewModel>
|
||||
this.WhenActivated(action => action(ViewModel!.SelectProfileCommand.Subscribe(Close)));
|
||||
}
|
||||
|
||||
private void SelectingItemsControl_OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
|
||||
private void SelectingItemsControl_OnSelectionChanged(object? _, SelectionChangedEventArgs e)
|
||||
{
|
||||
ViewModel!.SelectedInstance = ViewModel.Instances[((string)e.AddedItems[0]!)!];
|
||||
ViewModel!.SelectedInstance = ViewModel.Instances[(string)e.AddedItems[0]!];
|
||||
ViewModel.RaisePropertyChanged(nameof(ViewModel.IsInstanceSelected));
|
||||
ViewModel.RaisePropertyChanged(nameof(ViewModel.SelectedInstance));
|
||||
}
|
||||
|
||||
@ -3,7 +3,6 @@
|
||||
xmlns:vm="using:VaultSmpInstaller.ViewModels"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
mc:Ignorable="d" d:DesignWidth="600" d:DesignHeight="400"
|
||||
x:Class="VaultSmpInstaller.Views.RemoveOverwolfWindow"
|
||||
x:DataType="vm:ThemeViewModel"
|
||||
|
||||
@ -1,13 +1,9 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Threading;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace VaultSmpInstaller.Views;
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Interactivity;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.Threading;
|
||||
|
||||
namespace VaultSmpInstaller.Views;
|
||||
|
||||
public partial class SuccessWindow : Window
|
||||
{
|
||||
private readonly MainWindow _mainWindow;
|
||||
public SuccessWindow() { }
|
||||
|
||||
private readonly MainWindow? _mainWindow;
|
||||
public SuccessWindow(MainWindow mainWindow)
|
||||
{
|
||||
InitializeComponent();
|
||||
@ -17,7 +17,7 @@ public partial class SuccessWindow : Window
|
||||
|
||||
private void Ok(object? sender, RoutedEventArgs e)
|
||||
{
|
||||
_mainWindow.ContinueInstalling.Set();
|
||||
_mainWindow?.ContinueInstalling.Set();
|
||||
Dispatcher.UIThread.Invoke(Close);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user