0
0
mirror of https://github.com/sp-tarkov/patcher.git synced 2025-02-13 02:10:47 -05:00

Replace ViewNavigator with ReactiveUI RouterState, Fix PatchHelper rasing progress changed with no remaining source files, fix view load race conditions

This commit is contained in:
IsWaffle 2021-12-28 19:44:25 -05:00
parent 6ef883958d
commit 25a3c270be
22 changed files with 264 additions and 93 deletions

View File

@ -1,14 +0,0 @@
using ReactiveUI;
namespace PatchClient.Models
{
public class ViewNavigator : ReactiveObject
{
private object _SelectedViewModel;
public object SelectedViewModel
{
get => _SelectedViewModel;
set => this.RaiseAndSetIfChanged(ref _SelectedViewModel, value);
}
}
}

View File

@ -1,6 +1,9 @@
using Avalonia; using Avalonia;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
using Splat;
using System; using System;
using ReactiveUI;
using System.Reflection;
namespace PatchClient namespace PatchClient
{ {
@ -15,9 +18,14 @@ namespace PatchClient
// Avalonia configuration, don't remove; also used by visual designer. // Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp() public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>() {
Locator.CurrentMutable.RegisterViewsForViewModels(Assembly.GetExecutingAssembly());
return AppBuilder.Configure<App>()
.UseReactiveUI()
.UsePlatformDetect() .UsePlatformDetect()
.LogToTrace() .LogToTrace()
.UseReactiveUI(); .UseReactiveUI();
} }
}
} }

View File

@ -1,13 +1,15 @@
using Avalonia; using Avalonia;
using PatchClient.Models;
using ReactiveUI; using ReactiveUI;
using Splat; using System.Reactive.Disposables;
using System.Windows.Input; using System.Windows.Input;
namespace PatchClient.ViewModels namespace PatchClient.ViewModels
{ {
public class MainWindowViewModel : ViewModelBase public class MainWindowViewModel : ReactiveObject, IActivatableViewModel, IScreen
{ {
public ViewModelActivator Activator { get; } = new ViewModelActivator();
public RoutingState Router { get; } = new RoutingState();
public ICommand CloseCommand => ReactiveCommand.Create(() => public ICommand CloseCommand => ReactiveCommand.Create(() =>
{ {
if (Application.Current.ApplicationLifetime is Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime desktopApp) if (Application.Current.ApplicationLifetime is Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime desktopApp)
@ -16,12 +18,12 @@ namespace PatchClient.ViewModels
} }
}); });
public ViewNavigator navigator { get; set; } = new ViewNavigator();
public MainWindowViewModel() public MainWindowViewModel()
{ {
navigator.SelectedViewModel = new PatcherViewModel(); this.WhenActivated((CompositeDisposable disposable) =>
{
Locator.CurrentMutable.RegisterConstant(navigator, typeof(ViewNavigator)); Router.Navigate.Execute(new PatcherViewModel(this));
});
} }
} }
} }

View File

@ -4,14 +4,14 @@ namespace PatchClient.ViewModels
{ {
public class MessageViewModel : ViewModelBase public class MessageViewModel : ViewModelBase
{ {
private string _InfoText; private string _InfoText = "";
public string InfoText public string InfoText
{ {
get => _InfoText; get => _InfoText;
set => this.RaiseAndSetIfChanged(ref _InfoText, value); set => this.RaiseAndSetIfChanged(ref _InfoText, value);
} }
public MessageViewModel(string Message) public MessageViewModel(IScreen Host, string Message) : base(Host)
{ {
InfoText = Message; InfoText = Message;
} }

View File

@ -1,11 +1,12 @@
using Avalonia; using Avalonia;
using Avalonia.Threading;
using PatchClient.Models; using PatchClient.Models;
using PatcherUtils; using PatcherUtils;
using ReactiveUI; using ReactiveUI;
using Splat;
using System; using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Reactive.Disposables;
using System.Threading.Tasks; using System.Threading.Tasks;
namespace PatchClient.ViewModels namespace PatchClient.ViewModels
@ -16,7 +17,7 @@ namespace PatchClient.ViewModels
public ObservableCollection<LineItemProgress> LineItems { get; set; } = new ObservableCollection<LineItemProgress>(); public ObservableCollection<LineItemProgress> LineItems { get; set; } = new ObservableCollection<LineItemProgress>();
private string _ProgressMessage; private string _ProgressMessage = "";
public string ProgressMessage public string ProgressMessage
{ {
get => _ProgressMessage; get => _ProgressMessage;
@ -30,35 +31,67 @@ namespace PatchClient.ViewModels
set => this.RaiseAndSetIfChanged(ref _PatchPercent, value); set => this.RaiseAndSetIfChanged(ref _PatchPercent, value);
} }
private string _PatchMessage; private string _PatchMessage = "";
public string PatchMessage public string PatchMessage
{ {
get => _PatchMessage; get => _PatchMessage;
set => this.RaiseAndSetIfChanged(ref _PatchMessage, value); set => this.RaiseAndSetIfChanged(ref _PatchMessage, value);
} }
private ViewNavigator navigator => Locator.Current.GetService<ViewNavigator>();
public PatcherViewModel() public PatcherViewModel(IScreen Host) : base(Host)
{ {
this.WhenActivated((CompositeDisposable disposables) =>
{
//Test();
RunPatcher(); RunPatcher();
});
} }
/// <summary>
/// A dumb testing method to see if things look right. Obsolete is used more like a warning here.
/// </summary>
[Obsolete]
private void Test()
{
Task.Run(async () =>
{
LineItem x = new LineItem("test 1", 30);
LineItem xx = new LineItem("test 2", 100);
LineItem xxx = new LineItem("test 3", 70);
LineItems.Add(new LineItemProgress(x));
LineItems.Add(new LineItemProgress(xx));
LineItems.Add(new LineItemProgress(xxx));
for (int i = 0; i <= 100; i++)
{
System.Threading.Thread.Sleep(20);
PatchPercent = i;
ProgressMessage = $"Patching @ {i}%";
foreach (var item in LineItems)
{
item.UpdateProgress(item.Total - i);
}
}
await NavigateToWithDelay(new MessageViewModel(HostScreen, "Test Complete"), 400);
});
}
private void RunPatcher() private void RunPatcher()
{ {
Task.Run(() => Task.Run(async() =>
{ {
//Slight delay to avoid some weird race condition in avalonia core, seems to be a bug, but also maybe I'm just stupid, idk -waffle
//Error without delay: An item with the same key has already been added. Key: [1, Avalonia.Controls.Generators.ItemContainerInfo]
System.Threading.Thread.Sleep(1000);
PatchHelper patcher = new PatchHelper(Environment.CurrentDirectory, null, LazyOperations.PatchFolder); PatchHelper patcher = new PatchHelper(Environment.CurrentDirectory, null, LazyOperations.PatchFolder);
patcher.ProgressChanged += patcher_ProgressChanged; patcher.ProgressChanged += patcher_ProgressChanged;
string message = patcher.ApplyPatches(); string message = patcher.ApplyPatches();
navigator.SelectedViewModel = new MessageViewModel(message).WithDelay(400); await NavigateToWithDelay(new MessageViewModel(HostScreen, message), 400);
}); });
} }

View File

@ -1,22 +1,72 @@
using PatchClient.Models; using Avalonia.Threading;
using ReactiveUI; using ReactiveUI;
using System;
using System.Threading.Tasks;
namespace PatchClient.ViewModels namespace PatchClient.ViewModels
{ {
public class ViewModelBase : ReactiveObject public class ViewModelBase : ReactiveObject, IActivatableViewModel, IRoutableViewModel
{ {
public ViewModelActivator Activator { get; } = new ViewModelActivator();
public string? UrlPathSegment => Guid.NewGuid().ToString().Substring(0, 7);
public IScreen HostScreen { get; }
/// <summary> /// <summary>
/// Delay the return of the viewmodel /// Delay the return of the viewmodel
/// </summary> /// </summary>
/// <param name="Milliseconds">The amount of time in milliseconds to delay</param> /// <param name="Milliseconds">The amount of time in milliseconds to delay</param>
/// <returns>The viewmodel after the delay time</returns> /// <returns>The viewmodel after the delay time</returns>
/// <remarks>Useful to delay the navigation to another view via the <see cref="ViewNavigator"/>. For instance, to allow an animation to complete.</remarks> /// <remarks>Useful to delay the navigation to another view. For instance, to allow an animation to complete.</remarks>
public ViewModelBase WithDelay(int Milliseconds) private async Task<ViewModelBase> WithDelay(int Milliseconds)
{ {
System.Threading.Thread.Sleep(Milliseconds); await Task.Delay(Milliseconds);
return this; return this;
} }
/// <summary>
/// Navigate to another viewmodel after a delay
/// </summary>
/// <param name="ViewModel"></param>
/// <param name="Milliseconds"></param>
/// <returns></returns>
public async Task NavigateToWithDelay(ViewModelBase ViewModel, int Milliseconds)
{
await Dispatcher.UIThread.InvokeAsync(async () =>
{
HostScreen.Router.Navigate.Execute(await ViewModel.WithDelay(Milliseconds));
});
}
/// <summary>
/// Navigate to another viewmodel
/// </summary>
/// <param name="ViewModel"></param>
public void NavigateTo(ViewModelBase ViewModel)
{
Dispatcher.UIThread.InvokeAsync(() =>
{
HostScreen.Router.Navigate.Execute(ViewModel);
});
}
/// <summary>
/// Navigate to the previous viewmodel
/// </summary>
public void NavigateBack()
{
Dispatcher.UIThread.InvokeAsync(() =>
{
HostScreen.Router.NavigateBack.Execute();
});
}
public ViewModelBase(IScreen Host)
{
HostScreen = Host;
}
} }
} }

View File

@ -4,6 +4,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:cc="using:PatchClient.CustomControls" xmlns:cc="using:PatchClient.CustomControls"
xmlns:rxui="using:Avalonia.ReactiveUI"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="PatchClient.Views.MainWindow" x:Class="PatchClient.Views.MainWindow"
Icon="/Assets/avalonia-logo.ico" Icon="/Assets/avalonia-logo.ico"
@ -29,9 +30,7 @@
<cc:TitleBar Title="Patch Client" <cc:TitleBar Title="Patch Client"
XButtonCommand="{Binding CloseCommand}"/> XButtonCommand="{Binding CloseCommand}"/>
<DockPanel LastChildFill="True" Grid.Row="1"> <rxui:RoutedViewHost Router="{Binding Router}" Grid.Row="1"/>
<ContentControl Content="{Binding navigator.SelectedViewModel}"/>
</DockPanel>
</Grid> </Grid>
</Window> </Window>

View File

@ -1,10 +1,12 @@
using Avalonia; using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using PatchClient.ViewModels;
using ReactiveUI;
namespace PatchClient.Views namespace PatchClient.Views
{ {
public partial class MainWindow : Window public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
{ {
public MainWindow() public MainWindow()
{ {
@ -16,6 +18,7 @@ namespace PatchClient.Views
private void InitializeComponent() private void InitializeComponent()
{ {
this.WhenActivated(disposables => { });
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
} }

View File

@ -1,9 +1,11 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using PatchClient.ViewModels;
using ReactiveUI;
namespace PatchClient.Views namespace PatchClient.Views
{ {
public partial class MessageView : UserControl public partial class MessageView : ReactiveUserControl<MessageViewModel>
{ {
public MessageView() public MessageView()
{ {
@ -12,6 +14,7 @@ namespace PatchClient.Views
private void InitializeComponent() private void InitializeComponent()
{ {
this.WhenActivated(disposables => { });
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
} }

View File

@ -1,9 +1,11 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using PatchClient.ViewModels;
using ReactiveUI;
namespace PatchClient.Views namespace PatchClient.Views
{ {
public partial class PatcherView : UserControl public partial class PatcherView : ReactiveUserControl<PatcherViewModel>
{ {
public PatcherView() public PatcherView()
{ {
@ -12,6 +14,7 @@ namespace PatchClient.Views
private void InitializeComponent() private void InitializeComponent()
{ {
this.WhenActivated(disposables => { });
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
} }

View File

@ -1,6 +1,9 @@
using Avalonia; using Avalonia;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
using Splat;
using System; using System;
using ReactiveUI;
using System.Reflection;
namespace PatchGenerator namespace PatchGenerator
{ {
@ -15,9 +18,14 @@ namespace PatchGenerator
// Avalonia configuration, don't remove; also used by visual designer. // Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp() public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>() {
Locator.CurrentMutable.RegisterViewsForViewModels(Assembly.GetExecutingAssembly());
return AppBuilder.Configure<App>()
.UseReactiveUI()
.UsePlatformDetect() .UsePlatformDetect()
.LogToTrace() .LogToTrace()
.UseReactiveUI(); .UseReactiveUI();
} }
}
} }

View File

@ -1,9 +1,7 @@
{ {
"profiles": { "profiles": {
"PatchGenerator": { "PatchGenerator": {
"commandName": "Project", "commandName": "Project"
"commandLineArgs": "\"OutputFolderName::Patcher_12.3.4.5_to_6.7.8.9\" \"SourceFolderPath::C:\\Users\\JohnO\\Desktop\\12.12.10.16338\" \"TargetFolderPath::C:\\Users\\JohnO\\Desktop\\12.11.7.15680\" \"AutoZip::True\"",
"workingDirectory": "C:\\Users\\JohnO\\Desktop\\Patcher\\"
} }
} }
} }

View File

@ -1,14 +1,17 @@
using Avalonia; using Avalonia;
using PatchGenerator.Models; using PatchGenerator.Models;
using ReactiveUI; using ReactiveUI;
using Splat; using System.Reactive;
using System.Windows.Input; using System.Reactive.Disposables;
namespace PatchGenerator.ViewModels namespace PatchGenerator.ViewModels
{ {
public class MainWindowViewModel : ViewModelBase public class MainWindowViewModel : ReactiveObject, IActivatableViewModel, IScreen
{ {
public ICommand CloseCommand => ReactiveCommand.Create(() => public RoutingState Router { get; } = new RoutingState();
public ViewModelActivator Activator { get; } = new ViewModelActivator();
public ReactiveCommand<Unit, Unit> CloseCommand => ReactiveCommand.Create(() =>
{ {
if (Application.Current.ApplicationLifetime is Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime desktopApp) if (Application.Current.ApplicationLifetime is Avalonia.Controls.ApplicationLifetimes.IClassicDesktopStyleApplicationLifetime desktopApp)
{ {
@ -16,10 +19,10 @@ namespace PatchGenerator.ViewModels
} }
}); });
public ViewNavigator navigator { get; set; } = new ViewNavigator();
public MainWindowViewModel(GenStartupArgs genArgs = null) public MainWindowViewModel(GenStartupArgs genArgs = null)
{ {
Locator.CurrentMutable.RegisterConstant(navigator, typeof(ViewNavigator)); this.WhenActivated((CompositeDisposable disposables) =>
{
if (genArgs != null && genArgs.ReadyToRun) if (genArgs != null && genArgs.ReadyToRun)
{ {
@ -30,11 +33,12 @@ namespace PatchGenerator.ViewModels
genInfo.PatchName = genArgs.OutputFolderName; genInfo.PatchName = genArgs.OutputFolderName;
genInfo.AutoZip = genArgs.AutoZip; genInfo.AutoZip = genArgs.AutoZip;
navigator.SelectedViewModel = new PatchGenerationViewModel(genInfo); Router.Navigate.Execute(new PatchGenerationViewModel(this, genInfo));
return; return;
} }
navigator.SelectedViewModel = new OptionsViewModel(); Router.Navigate.Execute(new OptionsViewModel(this));
});
} }
} }
} }

View File

@ -1,5 +1,5 @@
using PatchGenerator.Models; using PatchGenerator.Models;
using Splat; using ReactiveUI;
namespace PatchGenerator.ViewModels namespace PatchGenerator.ViewModels
{ {
@ -7,9 +7,7 @@ namespace PatchGenerator.ViewModels
{ {
public PatchGenInfo GenerationInfo { get; set; } = new PatchGenInfo(); public PatchGenInfo GenerationInfo { get; set; } = new PatchGenInfo();
private ViewNavigator navigator => Locator.Current.GetService<ViewNavigator>(); public OptionsViewModel(IScreen Host) : base(Host)
public OptionsViewModel()
{ {
GenerationInfo.SourceFolderPath = "Drop SOURCE folder here"; GenerationInfo.SourceFolderPath = "Drop SOURCE folder here";
GenerationInfo.TargetFolderPath = "Drop TARGET folder here"; GenerationInfo.TargetFolderPath = "Drop TARGET folder here";
@ -17,7 +15,7 @@ namespace PatchGenerator.ViewModels
public void GeneratePatches() public void GeneratePatches()
{ {
navigator.SelectedViewModel = new PatchGenerationViewModel(GenerationInfo); NavigateTo(new PatchGenerationViewModel(HostScreen, GenerationInfo));
} }
} }
} }

View File

@ -8,6 +8,7 @@ using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Reactive.Disposables;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -42,7 +43,7 @@ namespace PatchGenerator.ViewModels
private Stopwatch patchGenStopwatch = new Stopwatch(); private Stopwatch patchGenStopwatch = new Stopwatch();
private readonly PatchGenInfo generationInfo; private readonly PatchGenInfo generationInfo;
public PatchGenerationViewModel(PatchGenInfo GenerationInfo) public PatchGenerationViewModel(IScreen Host, PatchGenInfo GenerationInfo) : base(Host)
{ {
generationInfo = GenerationInfo; generationInfo = GenerationInfo;
@ -55,17 +56,16 @@ namespace PatchGenerator.ViewModels
}); });
} }
this.WhenActivated((CompositeDisposable dissposables) =>
{
GeneratePatches(); GeneratePatches();
});
} }
public void GeneratePatches() public void GeneratePatches()
{ {
Task.Run(() => Task.Run(() =>
{ {
//Slight delay to avoid some weird race condition in avalonia core, seems to be a bug, but also maybe I'm just stupid, idk -waffle
//Error without delay: An item with the same key has already been added. Key: [1, Avalonia.Controls.Generators.ItemContainerInfo]
System.Threading.Thread.Sleep(1000);
string patchOutputFolder = Path.Join(generationInfo.PatchName.FromCwd(), LazyOperations.PatchFolder); string patchOutputFolder = Path.Join(generationInfo.PatchName.FromCwd(), LazyOperations.PatchFolder);
PatchHelper patcher = new PatchHelper(generationInfo.SourceFolderPath, generationInfo.TargetFolderPath, patchOutputFolder); PatchHelper patcher = new PatchHelper(generationInfo.SourceFolderPath, generationInfo.TargetFolderPath, patchOutputFolder);

View File

@ -1,8 +1,72 @@
using Avalonia.Threading;
using ReactiveUI; using ReactiveUI;
using System;
using System.Threading.Tasks;
namespace PatchGenerator.ViewModels namespace PatchGenerator.ViewModels
{ {
public class ViewModelBase : ReactiveObject public class ViewModelBase : ReactiveObject, IActivatableViewModel, IRoutableViewModel
{ {
public ViewModelActivator Activator { get; } = new ViewModelActivator();
public string? UrlPathSegment => Guid.NewGuid().ToString().Substring(0, 7);
public IScreen HostScreen { get; }
/// <summary>
/// Delay the return of the viewmodel
/// </summary>
/// <param name="Milliseconds">The amount of time in milliseconds to delay</param>
/// <returns>The viewmodel after the delay time</returns>
/// <remarks>Useful to delay the navigation to another view. For instance, to allow an animation to complete.</remarks>
private async Task<ViewModelBase> WithDelay(int Milliseconds)
{
await Task.Delay(Milliseconds);
return this;
} }
/// <summary>
/// Navigate to another viewmodel after a delay
/// </summary>
/// <param name="ViewModel"></param>
/// <param name="Milliseconds"></param>
/// <returns></returns>
public async Task NavigateToWithDelay(ViewModelBase ViewModel, int Milliseconds)
{
await Dispatcher.UIThread.InvokeAsync(async () =>
{
HostScreen.Router.Navigate.Execute(await ViewModel.WithDelay(Milliseconds));
});
}
/// <summary>
/// Navigate to another viewmodel
/// </summary>
/// <param name="ViewModel"></param>
public void NavigateTo(ViewModelBase ViewModel)
{
Dispatcher.UIThread.InvokeAsync(() =>
{
HostScreen.Router.Navigate.Execute(ViewModel);
});
}
/// <summary>
/// Navigate to the previous viewmodel
/// </summary>
public void NavigateBack()
{
Dispatcher.UIThread.InvokeAsync(() =>
{
HostScreen.Router.NavigateBack.Execute();
});
}
public ViewModelBase(IScreen Host)
{
HostScreen = Host;
}
}
} }

View File

@ -4,6 +4,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:cc="using:PatchGenerator.CustomControls" xmlns:cc="using:PatchGenerator.CustomControls"
xmlns:rxui="using:Avalonia.ReactiveUI"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="PatchGenerator.Views.MainWindow" x:Class="PatchGenerator.Views.MainWindow"
Icon="/Assets/avalonia-logo.ico" Icon="/Assets/avalonia-logo.ico"
@ -28,9 +29,7 @@
<cc:TitleBar Title="Patch Generator" <cc:TitleBar Title="Patch Generator"
XButtonCommand="{Binding CloseCommand}"/> XButtonCommand="{Binding CloseCommand}"/>
<DockPanel LastChildFill="True" Grid.Row="1"> <rxui:RoutedViewHost Router="{Binding Router}" Grid.Row="1" />
<ContentControl Content="{Binding navigator.SelectedViewModel}"/>
</DockPanel>
</Grid> </Grid>

View File

@ -1,10 +1,12 @@
using Avalonia; using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using PatchGenerator.ViewModels;
using ReactiveUI;
namespace PatchGenerator.Views namespace PatchGenerator.Views
{ {
public partial class MainWindow : Window public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
{ {
public MainWindow() public MainWindow()
{ {
@ -16,6 +18,7 @@ namespace PatchGenerator.Views
private void InitializeComponent() private void InitializeComponent()
{ {
this.WhenActivated(disposables => { });
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
} }

View File

@ -1,9 +1,11 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using PatchGenerator.ViewModels;
using ReactiveUI;
namespace PatchGenerator.Views namespace PatchGenerator.Views
{ {
public partial class OptionsView : UserControl public partial class OptionsView : ReactiveUserControl<OptionsViewModel>
{ {
public OptionsView() public OptionsView()
{ {
@ -12,6 +14,7 @@ namespace PatchGenerator.Views
private void InitializeComponent() private void InitializeComponent()
{ {
this.WhenActivated(disposables => { });
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
} }

View File

@ -1,10 +1,13 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using PatchGenerator.AttachedProperties; using PatchGenerator.AttachedProperties;
using PatchGenerator.ViewModels;
using ReactiveUI;
namespace PatchGenerator.Views namespace PatchGenerator.Views
{ {
public partial class PatchGenerationView : UserControl public partial class PatchGenerationView : ReactiveUserControl<PatchGenerationViewModel>
{ {
public PatchGenerationView() public PatchGenerationView()
{ {
@ -13,6 +16,7 @@ namespace PatchGenerator.Views
private void InitializeComponent() private void InitializeComponent()
{ {
this.WhenActivated(disposables => { });
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }

View File

@ -242,6 +242,9 @@ namespace PatcherUtils
//Any remaining source files do not exist in the target folder and can be removed. //Any remaining source files do not exist in the target folder and can be removed.
//reset progress info //reset progress info
if (SourceFiles.Count == 0) return true;
RaiseProgressChanged(0, SourceFiles.Count, "Processing .del files..."); RaiseProgressChanged(0, SourceFiles.Count, "Processing .del files...");
filesProcessed = 0; filesProcessed = 0;
fileCountTotal = SourceFiles.Count; fileCountTotal = SourceFiles.Count;

Binary file not shown.