diff --git a/ModpackUpdater.Apps.Client.Gui/App.axaml b/ModpackUpdater.Apps.Client.Gui/App.axaml
index 08720a6..dcd8b1c 100644
--- a/ModpackUpdater.Apps.Client.Gui/App.axaml
+++ b/ModpackUpdater.Apps.Client.Gui/App.axaml
@@ -1,11 +1,11 @@
-
+ xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+ x:Class="ModpackUpdater.Apps.Client.Gui.App"
+ RequestedThemeVariant="Default">
+
-
+
\ No newline at end of file
diff --git a/ModpackUpdater.Apps.Client.Gui/App.axaml.cs b/ModpackUpdater.Apps.Client.Gui/App.axaml.cs
index 49080d1..111c3e4 100644
--- a/ModpackUpdater.Apps.Client.Gui/App.axaml.cs
+++ b/ModpackUpdater.Apps.Client.Gui/App.axaml.cs
@@ -1,5 +1,6 @@
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
+using Avalonia.Data.Core.Plugins;
using Avalonia.Markup.Xaml;
namespace ModpackUpdater.Apps.Client.Gui;
@@ -15,7 +16,26 @@ public partial class App : Application
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
- desktop.MainWindow = new MainForm();
+ {
+ DisableAvaloniaDataAnnotationValidation();
+ desktop.MainWindow = new MainView
+ {
+ DataContext = new MainViewModel(),
+ };
+ }
base.OnFrameworkInitializationCompleted();
}
+
+ private void DisableAvaloniaDataAnnotationValidation()
+ {
+ // Get an array of plugins to remove
+ var dataValidationPluginsToRemove =
+ BindingPlugins.DataValidators.OfType().ToArray();
+
+ // remove each entry found
+ foreach (var plugin in dataValidationPluginsToRemove)
+ {
+ BindingPlugins.DataValidators.Remove(plugin);
+ }
+ }
}
\ No newline at end of file
diff --git a/ModpackUpdater.Apps.Client.Gui/MainForm.axaml b/ModpackUpdater.Apps.Client.Gui/MainView.axaml
similarity index 61%
rename from ModpackUpdater.Apps.Client.Gui/MainForm.axaml
rename to ModpackUpdater.Apps.Client.Gui/MainView.axaml
index 8891503..75e37b5 100644
--- a/ModpackUpdater.Apps.Client.Gui/MainForm.axaml
+++ b/ModpackUpdater.Apps.Client.Gui/MainView.axaml
@@ -4,16 +4,23 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:lang="clr-namespace:ModpackUpdater.Apps.Client.Gui.LangRes"
xmlns:pilz="https://git.pilzinsel64.de/pilz-framework/pilz"
+ xmlns:gui="clr-namespace:ModpackUpdater.Apps.Client.Gui"
xmlns:symbols="clr-namespace:Pilz.UI.Symbols;assembly=Pilz.UI"
mc:Ignorable="d"
- x:Class="ModpackUpdater.Apps.Client.Gui.MainForm"
+ x:Class="ModpackUpdater.Apps.Client.Gui.MainView"
+ x:DataType="gui:MainViewModel"
+ x:Name="window"
Width="520"
SizeToContent="Height"
WindowStartupLocation="CenterScreen"
CanMaximize="false"
Title="Minecraft Modpack Updater"
Icon="/Assets/app.ico"
- Loaded="MainForm_Loaded">
+ Loaded="Control_OnLoaded">
+
+
+
+
+
+
+
+
+
+
+
@@ -31,11 +45,11 @@
-
+
-
-
+
+
@@ -46,7 +60,7 @@
Margin="3"
VerticalAlignment="Center"
Watermark="C:\..."
- TextChanged="TextBoxMinecraftProfileFolder_TextChanged"/>
+ Text="{Binding MinecraftProfileFolder}"/>
+ Text="{Binding ModpackConfigUrl}"/>
+ Text="{Binding InstallKey}"
+ IsVisible="{Binding CanUseExtrasKey}"/>
+ Click="ButtonSearchProfileFolder_Click">
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Command="{Binding CheckForUpdatesCommand}"
+ IsEnabled="{Binding CanUpdate}"/>
+ Command="{Binding InstallCommand}"
+ IsEnabled="{Binding CanUpdate}">
+
-
+
diff --git a/ModpackUpdater.Apps.Client.Gui/MainView.axaml.cs b/ModpackUpdater.Apps.Client.Gui/MainView.axaml.cs
new file mode 100644
index 0000000..241acf1
--- /dev/null
+++ b/ModpackUpdater.Apps.Client.Gui/MainView.axaml.cs
@@ -0,0 +1,51 @@
+using System.Reflection;
+using Avalonia.Controls;
+using Avalonia.Interactivity;
+using Avalonia.Platform.Storage;
+using Avalonia.Threading;
+using ModpackUpdater.Apps.Client.Gui.LangRes;
+using Pilz.Extensions;
+using Pilz.UI.Symbols;
+
+namespace ModpackUpdater.Apps.Client.Gui;
+
+public partial class MainView : Window
+{
+ public MainViewModel Model => DataContext as MainViewModel ?? throw new NullReferenceException();
+
+ public MainView()
+ {
+ InitializeComponent();
+
+ Title = $"{Title} (v{Assembly.GetExecutingAssembly().GetAppVersion().ToShortString()})";
+
+ ButtonSearchProfileFolder.ImageSource = AppGlobals.Symbols.GetImageSource(AppSymbols.opened_folder);
+ ButtonCheckForUpdates.ImageSource = AppGlobals.Symbols.GetImageSource(AppSymbols.update_done);
+ ButtonInstall.ImageSource = AppGlobals.Symbols.GetImageSource(AppSymbols.software_installer);
+ MenuItemRepair.Icon = AppGlobals.Symbols.GetImage(AppSymbols.wrench, SymbolSize.Small);
+ }
+
+ private async void InitializeViewModel()
+ {
+ await Model.CheckForUpdates(this);
+ await Model.Initialize();
+ }
+
+ private void Control_OnLoaded(object? sender, RoutedEventArgs e)
+ {
+ Dispatcher.UIThread.Post(InitializeViewModel, DispatcherPriority.Background);
+ }
+
+ private async void ButtonSearchProfileFolder_Click(object? sender, RoutedEventArgs e)
+ {
+ var filePaths = await StorageProvider.OpenFolderPickerAsync(new FolderPickerOpenOptions
+ {
+ Title = GeneralLangRes.SelectMinecraftProfileFolder,
+ SuggestedStartLocation = await StorageProvider.TryGetFolderFromPathAsync(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData)),
+ AllowMultiple = false,
+ });
+
+ if (filePaths.Count >= 1)
+ Model.MinecraftProfileFolder = filePaths[0].Path.AbsolutePath;
+ }
+}
\ No newline at end of file
diff --git a/ModpackUpdater.Apps.Client.Gui/MainForm.axaml.cs b/ModpackUpdater.Apps.Client.Gui/MainViewModel.cs
similarity index 51%
rename from ModpackUpdater.Apps.Client.Gui/MainForm.axaml.cs
rename to ModpackUpdater.Apps.Client.Gui/MainViewModel.cs
index 18bbac0..61a1a6e 100644
--- a/ModpackUpdater.Apps.Client.Gui/MainForm.axaml.cs
+++ b/ModpackUpdater.Apps.Client.Gui/MainViewModel.cs
@@ -1,84 +1,140 @@
-using System.Diagnostics;
-using System.Reflection;
+using System.Collections.ObjectModel;
+using System.Diagnostics;
+using System.Windows.Input;
using Avalonia.Controls;
-using Avalonia.Interactivity;
using Avalonia.Media;
-using Avalonia.Platform.Storage;
-using Avalonia.Threading;
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
using ModpackUpdater.Apps.Client.Gui.LangRes;
using ModpackUpdater.Manager;
-using Pilz.Extensions;
using Pilz.Extensions.Collections;
-using Pilz.UI.Symbols;
namespace ModpackUpdater.Apps.Client.Gui;
-public partial class MainForm : Window
+public partial class MainViewModel : ObservableObject
{
- private readonly MenuFlyout menuFlyoutSearchProfileFolder = new();
+ public class EmptyRecentFilesItem;
+
+ public class RecentFilesItem(string path)
+ {
+ public string Path => path;
+ public string Display => path.Length > 50 ? $"...{path[^50..]}" : path;
+ }
+
private readonly UpdateCheckOptions updateOptions = new();
private ModpackInfo modpackInfo = new();
private ModpackConfig updateConfig = new();
private ModpackFeatures? features;
private UpdateCheckResult? lastUpdateCheckResult;
- private bool currentUpdating;
- private bool loadingData;
+
+ [ObservableProperty] private string? minecraftProfileFolder;
+ [ObservableProperty] private string? modpackConfigUrl;
+ [ObservableProperty] private string? installKey;
+ [ObservableProperty] private string statusText = "-";
+ [ObservableProperty] private IImage? statusImage;
+ [ObservableProperty] private bool hasInitialized;
+ [ObservableProperty] private bool isUpdating;
+ [ObservableProperty] private bool loadingData;
+ [ObservableProperty] private bool canUpdate;
+ [ObservableProperty] private bool canUseExtrasKey;
- public MainForm()
+ public ObservableCollection