Compare commits
30 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
f089629c74
|
|||
|
836282c6ac
|
|||
|
ee6b8d443d
|
|||
|
5947f81307
|
|||
| 32c4065940 | |||
| 8c29cf9e8a | |||
|
16b1a655aa
|
|||
|
12b5a63003
|
|||
|
035d2eeb9b
|
|||
|
eaaca4ddb8
|
|||
|
c1960abe3a
|
|||
|
cbd4b1c346
|
|||
|
db108fe36e
|
|||
|
bd8a08f03c
|
|||
|
7e2d7f56df
|
|||
|
c7b2fff7e7
|
|||
|
a6a3d9d5a9
|
|||
|
5a90cc7e82
|
|||
|
1e3d2701fc
|
|||
|
f5e84b6da7
|
|||
|
c864d9125a
|
|||
|
|
e7aa79db64 | ||
|
|
c0f013a6c5 | ||
|
|
f21e31ebcc | ||
|
|
0ae2a780b0 | ||
|
|
474f76df4a | ||
|
|
6454d97173 | ||
|
|
e57d2316de | ||
|
2cbe25e0f8
|
|||
|
86f93cf3d7
|
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
[submodule "publish-scripts"]
|
||||||
|
path = publish-scripts
|
||||||
|
url = https://git.pilzinsel64.de/Pilz.NET/publish-scripts.git
|
||||||
@@ -16,6 +16,10 @@
|
|||||||
<NoWarn>1591</NoWarn>
|
<NoWarn>1591</NoWarn>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<PropertyGroup Condition="'$(Configuration)'=='Debug'">
|
||||||
|
<DefineConstants>$(DefineConstants);DISABLE_UPDATE</DefineConstants>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
<PropertyGroup Condition="'$(Configuration)'=='Release'">
|
||||||
<DebugSymbols>False</DebugSymbols>
|
<DebugSymbols>False</DebugSymbols>
|
||||||
<DebugType>None</DebugType>
|
<DebugType>None</DebugType>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls.ApplicationLifetimes;
|
using Avalonia.Controls.ApplicationLifetimes;
|
||||||
|
using Avalonia.Data.Core.Plugins;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
namespace ModpackUpdater.Apps.Client.Gui;
|
namespace ModpackUpdater.Apps.Client.Gui;
|
||||||
@@ -15,7 +16,26 @@ public partial class App : Application
|
|||||||
public override void OnFrameworkInitializationCompleted()
|
public override void OnFrameworkInitializationCompleted()
|
||||||
{
|
{
|
||||||
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
desktop.MainWindow = new MainForm();
|
{
|
||||||
|
DisableAvaloniaDataAnnotationValidation();
|
||||||
|
desktop.MainWindow = new MainView
|
||||||
|
{
|
||||||
|
DataContext = new MainViewModel(),
|
||||||
|
};
|
||||||
|
}
|
||||||
base.OnFrameworkInitializationCompleted();
|
base.OnFrameworkInitializationCompleted();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void DisableAvaloniaDataAnnotationValidation()
|
||||||
|
{
|
||||||
|
// Get an array of plugins to remove
|
||||||
|
var dataValidationPluginsToRemove =
|
||||||
|
BindingPlugins.DataValidators.OfType<DataAnnotationsValidationPlugin>().ToArray();
|
||||||
|
|
||||||
|
// remove each entry found
|
||||||
|
foreach (var plugin in dataValidationPluginsToRemove)
|
||||||
|
{
|
||||||
|
BindingPlugins.DataValidators.Remove(plugin);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -7,19 +7,21 @@ public class AppConfig : ISettingsNode, ISettingsIdentifier
|
|||||||
{
|
{
|
||||||
public static string Identifier => "pilz.appconfig";
|
public static string Identifier => "pilz.appconfig";
|
||||||
|
|
||||||
public string? LastMinecraftProfilePath { get; set; }
|
public List<string> RecentMinecraftProfilePaths { get; } = [];
|
||||||
|
|
||||||
[JsonIgnore, Obsolete]
|
[JsonProperty, Obsolete]
|
||||||
public string? ConfigFilePath { get; private set; }
|
private string? LastMinecraftProfilePath
|
||||||
[JsonProperty("ConfigFilePath"), Obsolete]
|
|
||||||
private string ConfigFilePathLegacy
|
|
||||||
{
|
{
|
||||||
set => ConfigFilePath = value;
|
set
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(value))
|
||||||
|
RecentMinecraftProfilePaths.Insert(0, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
{
|
{
|
||||||
LastMinecraftProfilePath = null;
|
RecentMinecraftProfilePaths.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AppConfig Instance => Program.Settings.Get<AppConfig>();
|
public static AppConfig Instance => Program.Settings.Get<AppConfig>();
|
||||||
|
|||||||
@@ -11,32 +11,46 @@ namespace ModpackUpdater.Apps.Client.Gui.LangRes {
|
|||||||
using System;
|
using System;
|
||||||
|
|
||||||
|
|
||||||
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
/// <summary>
|
||||||
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
/// A strongly-typed resource class, for looking up localized strings, etc.
|
||||||
[System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
/// </summary>
|
||||||
|
// This class was auto-generated by the StronglyTypedResourceBuilder
|
||||||
|
// class via a tool like ResGen or Visual Studio.
|
||||||
|
// To add or remove a member, edit your .ResX file then rerun ResGen
|
||||||
|
// with the /str option, or rebuild your VS project.
|
||||||
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")]
|
||||||
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
public class GeneralLangRes {
|
public class GeneralLangRes {
|
||||||
|
|
||||||
private static System.Resources.ResourceManager resourceMan;
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
private static System.Globalization.CultureInfo resourceCulture;
|
private static global::System.Globalization.CultureInfo resourceCulture;
|
||||||
|
|
||||||
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
[global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
|
||||||
internal GeneralLangRes() {
|
internal GeneralLangRes() {
|
||||||
}
|
}
|
||||||
|
|
||||||
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
|
/// <summary>
|
||||||
public static System.Resources.ResourceManager ResourceManager {
|
/// Returns the cached ResourceManager instance used by this class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
public static global::System.Resources.ResourceManager ResourceManager {
|
||||||
get {
|
get {
|
||||||
if (object.Equals(null, resourceMan)) {
|
if (object.ReferenceEquals(resourceMan, null)) {
|
||||||
System.Resources.ResourceManager temp = new System.Resources.ResourceManager("ModpackUpdater.Apps.Client.Gui.LangRes.GeneralLangRes", typeof(GeneralLangRes).Assembly);
|
global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ModpackUpdater.Apps.Client.Gui.LangRes.GeneralLangRes", typeof(GeneralLangRes).Assembly);
|
||||||
resourceMan = temp;
|
resourceMan = temp;
|
||||||
}
|
}
|
||||||
return resourceMan;
|
return resourceMan;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
|
/// <summary>
|
||||||
public static System.Globalization.CultureInfo Culture {
|
/// Overrides the current thread's CurrentUICulture property for all
|
||||||
|
/// resource lookups using this strongly typed resource class.
|
||||||
|
/// </summary>
|
||||||
|
[global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
|
||||||
|
public static global::System.Globalization.CultureInfo Culture {
|
||||||
get {
|
get {
|
||||||
return resourceCulture;
|
return resourceCulture;
|
||||||
}
|
}
|
||||||
@@ -45,118 +59,184 @@ namespace ModpackUpdater.Apps.Client.Gui.LangRes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to An update is available!.
|
||||||
|
/// </summary>
|
||||||
public static string AnUpdateIsAvailable {
|
public static string AnUpdateIsAvailable {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("AnUpdateIsAvailable", resourceCulture);
|
return ResourceManager.GetString("AnUpdateIsAvailable", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Check for updates.
|
||||||
|
/// </summary>
|
||||||
public static string CheckForUpdates {
|
public static string CheckForUpdates {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("CheckForUpdates", resourceCulture);
|
return ResourceManager.GetString("CheckForUpdates", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Checking for Updates....
|
||||||
|
/// </summary>
|
||||||
public static string CheckingForUpdates {
|
public static string CheckingForUpdates {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("CheckingForUpdates", resourceCulture);
|
return ResourceManager.GetString("CheckingForUpdates", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Config incomplete or not loaded!.
|
||||||
|
/// </summary>
|
||||||
public static string ConfigIncompleteOrNotLoaded {
|
public static string ConfigIncompleteOrNotLoaded {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("ConfigIncompleteOrNotLoaded", resourceCulture);
|
return ResourceManager.GetString("ConfigIncompleteOrNotLoaded", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Downloading program update....
|
||||||
|
/// </summary>
|
||||||
public static string DownloadProgramUpdate {
|
public static string DownloadProgramUpdate {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("DownloadProgramUpdate", resourceCulture);
|
return ResourceManager.GetString("DownloadProgramUpdate", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Error on update check or while updating!.
|
||||||
|
/// </summary>
|
||||||
public static string ErrorOnUpdateCheckOrUpdating {
|
public static string ErrorOnUpdateCheckOrUpdating {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("ErrorOnUpdateCheckOrUpdating", resourceCulture);
|
return ResourceManager.GetString("ErrorOnUpdateCheckOrUpdating", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Everything is right and up-to-date..
|
||||||
|
/// </summary>
|
||||||
public static string EverythingIsRightAndUpToDate {
|
public static string EverythingIsRightAndUpToDate {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("EverythingIsRightAndUpToDate", resourceCulture);
|
return ResourceManager.GetString("EverythingIsRightAndUpToDate", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Install.
|
||||||
|
/// </summary>
|
||||||
public static string Install {
|
public static string Install {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("Install", resourceCulture);
|
return ResourceManager.GetString("Install", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Installation key.
|
||||||
|
/// </summary>
|
||||||
public static string InstallationKey {
|
public static string InstallationKey {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("InstallationKey", resourceCulture);
|
return ResourceManager.GetString("InstallationKey", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Installation key seems to be invalid.
|
||||||
|
/// </summary>
|
||||||
|
public static string InstallationKeyNotValid {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("InstallationKeyNotValid", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Installing....
|
||||||
|
/// </summary>
|
||||||
public static string Installing {
|
public static string Installing {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("Installing", resourceCulture);
|
return ResourceManager.GetString("Installing", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Minecraft profile.
|
||||||
|
/// </summary>
|
||||||
public static string MinecraftProfile {
|
public static string MinecraftProfile {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("MinecraftProfile", resourceCulture);
|
return ResourceManager.GetString("MinecraftProfile", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Minecraft profile folder seems to be not valid..
|
||||||
|
/// </summary>
|
||||||
public static string MinecraftProfileFolderSeemsInvalid {
|
public static string MinecraftProfileFolderSeemsInvalid {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("MinecraftProfileFolderSeemsInvalid", resourceCulture);
|
return ResourceManager.GetString("MinecraftProfileFolderSeemsInvalid", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Modpack config url.
|
||||||
|
/// </summary>
|
||||||
public static string ModpackConfigUrl {
|
public static string ModpackConfigUrl {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("ModpackConfigUrl", resourceCulture);
|
return ResourceManager.GetString("ModpackConfigUrl", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to No recent profiles available..
|
||||||
|
/// </summary>
|
||||||
|
public static string NoRecentProfilesAvailable {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("NoRecentProfilesAvailable", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Repair.
|
||||||
|
/// </summary>
|
||||||
public static string Repair {
|
public static string Repair {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("Repair", resourceCulture);
|
return ResourceManager.GetString("Repair", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Select.
|
||||||
|
/// </summary>
|
||||||
public static string Select {
|
public static string Select {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("Select", resourceCulture);
|
return ResourceManager.GetString("Select", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Select the minecraft profile folder (usually named .minecraft).
|
||||||
|
/// </summary>
|
||||||
public static string SelectMinecraftProfileFolder {
|
public static string SelectMinecraftProfileFolder {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("SelectMinecraftProfileFolder", resourceCulture);
|
return ResourceManager.GetString("SelectMinecraftProfileFolder", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to Status.
|
||||||
|
/// </summary>
|
||||||
public static string Status {
|
public static string Status {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("Status", resourceCulture);
|
return ResourceManager.GetString("Status", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Looks up a localized string similar to The update servers are in maintenance..
|
||||||
|
/// </summary>
|
||||||
public static string UpdateServerInMaintenance {
|
public static string UpdateServerInMaintenance {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("UpdateServerInMaintenance", resourceCulture);
|
return ResourceManager.GetString("UpdateServerInMaintenance", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string InstallationKeyNotValid {
|
|
||||||
get {
|
|
||||||
return ResourceManager.GetString("InstallationKeyNotValid", resourceCulture);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -174,4 +174,7 @@
|
|||||||
<data name="InstallationKeyNotValid" xml:space="preserve">
|
<data name="InstallationKeyNotValid" xml:space="preserve">
|
||||||
<value>Installation key seems to be invalid</value>
|
<value>Installation key seems to be invalid</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="NoRecentProfilesAvailable" xml:space="preserve">
|
||||||
|
<value>No recent profiles available.</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -1,341 +0,0 @@
|
|||||||
using System.Diagnostics;
|
|
||||||
using System.Reflection;
|
|
||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Interactivity;
|
|
||||||
using Avalonia.Media;
|
|
||||||
using Avalonia.Platform.Storage;
|
|
||||||
using Avalonia.Threading;
|
|
||||||
using ModpackUpdater.Apps.Client.Gui.LangRes;
|
|
||||||
using ModpackUpdater.Manager;
|
|
||||||
using MsBox.Avalonia;
|
|
||||||
using MsBox.Avalonia.Enums;
|
|
||||||
using Pilz;
|
|
||||||
using Pilz.Extensions;
|
|
||||||
using Pilz.Runtime;
|
|
||||||
using Pilz.UI.Symbols;
|
|
||||||
using Pilz.Updating.Client;
|
|
||||||
|
|
||||||
namespace ModpackUpdater.Apps.Client.Gui;
|
|
||||||
|
|
||||||
public partial class MainForm : Window
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
private int curOptionsRow = 3;
|
|
||||||
|
|
||||||
public MainForm()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
Title = $"{Title} (v{Assembly.GetExecutingAssembly().GetAppVersion().ToShortString()})";
|
|
||||||
|
|
||||||
Closing += MainForm_Closing;
|
|
||||||
Loaded += MainForm_Loaded;
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
ClearStatus();
|
|
||||||
LoadProfileToUi();
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Features
|
|
||||||
|
|
||||||
private void SetStatus(string statusText, IImage? image)
|
|
||||||
{
|
|
||||||
TextStatus.Text = statusText;
|
|
||||||
ImageStatus.Source = image;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ClearStatus()
|
|
||||||
{
|
|
||||||
TextStatus.Text = "-";
|
|
||||||
ImageStatus.Source = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LoadProfileToUi()
|
|
||||||
{
|
|
||||||
loadingData = true;
|
|
||||||
|
|
||||||
TextBoxMinecraftProfileFolder.Text = modpackInfo.LocalPath ?? AppConfig.Instance.LastMinecraftProfilePath ?? TextBoxMinecraftProfileFolder.Text;
|
|
||||||
TextBoxModpackConfig.Text = modpackInfo.ConfigUrl ?? TextBoxModpackConfig.Text;
|
|
||||||
TextBoxInstallKey.Text = modpackInfo.ExtrasKey ?? TextBoxInstallKey.Text;
|
|
||||||
|
|
||||||
Dispatcher.UIThread.Post(() => loadingData = false, DispatcherPriority.Background);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void LoadOptionsToUi()
|
|
||||||
{
|
|
||||||
//foreach (var set in )
|
|
||||||
//{
|
|
||||||
// // ...
|
|
||||||
//}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void CheckStatusAndUpdate(bool loadProfileToUi)
|
|
||||||
{
|
|
||||||
if (CheckStatus(loadProfileToUi))
|
|
||||||
await ExecuteUpdate(false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool CheckStatus(bool loadProfileToUi)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
modpackInfo = ModpackInfo.TryLoad(TextBoxMinecraftProfileFolder.Text?.Trim());
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
if (loadProfileToUi)
|
|
||||||
LoadProfileToUi();
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
updateConfig = ModpackConfig.LoadFromUrl(TextBoxModpackConfig.Text);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// Ignore
|
|
||||||
}
|
|
||||||
|
|
||||||
features = new(updateConfig);
|
|
||||||
modpackInfo.ExtrasKey = TextBoxInstallKey.Text?.Trim();
|
|
||||||
if (!features.IsInvalid() && !string.IsNullOrWhiteSpace(TextBoxInstallKey.Text) && !AllowExtras())
|
|
||||||
{
|
|
||||||
SetStatus(GeneralLangRes.InstallationKeyNotValid, AppGlobals.Symbols.GetImageSource(AppSymbols.general_warning_sign));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
LabelInstallKey.IsVisible = TextBoxInstallKey.IsVisible = !string.IsNullOrWhiteSpace(updateConfig.UnleashApiUrl);
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(TextBoxMinecraftProfileFolder.Text) /*|| modpackInfo.Valid*/)
|
|
||||||
{
|
|
||||||
SetStatus(GeneralLangRes.MinecraftProfileFolderSeemsInvalid, AppGlobals.Symbols.GetImageSource(AppSymbols.general_warning_sign));
|
|
||||||
ButtonCheckForUpdates.IsEnabled = false;
|
|
||||||
ButtonInstall.IsEnabled = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (string.IsNullOrWhiteSpace(TextBoxModpackConfig.Text))
|
|
||||||
{
|
|
||||||
SetStatus(GeneralLangRes.ConfigIncompleteOrNotLoaded, AppGlobals.Symbols.GetImageSource(AppSymbols.general_warning_sign));
|
|
||||||
ButtonCheckForUpdates.IsEnabled = false;
|
|
||||||
ButtonInstall.IsEnabled = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else if (updateConfig.Maintenance && !updateOptions.IgnoreMaintenance)
|
|
||||||
{
|
|
||||||
SetStatus(GeneralLangRes.UpdateServerInMaintenance, AppGlobals.Symbols.GetImageSource(AppSymbols.services));
|
|
||||||
ButtonCheckForUpdates.IsEnabled = false;
|
|
||||||
ButtonInstall.IsEnabled = false;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
LoadOptionsToUi();
|
|
||||||
ButtonCheckForUpdates.IsEnabled = true;
|
|
||||||
ButtonInstall.IsEnabled = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async Task ExecuteUpdate(bool doInstall, bool repair)
|
|
||||||
{
|
|
||||||
// Ensure set extras key
|
|
||||||
modpackInfo.ExtrasKey = TextBoxInstallKey.Text?.Trim();
|
|
||||||
|
|
||||||
var updater = new ModpackInstaller(updateConfig, modpackInfo);
|
|
||||||
updater.InstallProgessUpdated += Update_InstallProgessUpdated;
|
|
||||||
updater.CheckingProgressUpdated += Updated_CheckingProgresssUpdated;
|
|
||||||
|
|
||||||
void error()
|
|
||||||
{
|
|
||||||
SetStatus(GeneralLangRes.ErrorOnUpdateCheckOrUpdating, AppGlobals.Symbols.GetImageSource(AppSymbols.close));
|
|
||||||
currentUpdating = false;
|
|
||||||
}
|
|
||||||
void installing()
|
|
||||||
{
|
|
||||||
SetStatus(GeneralLangRes.Installing, AppGlobals.Symbols.GetImageSource(AppSymbols.software_installer));
|
|
||||||
currentUpdating = true;
|
|
||||||
}
|
|
||||||
void updatesAvailable()
|
|
||||||
{
|
|
||||||
SetStatus(GeneralLangRes.AnUpdateIsAvailable, AppGlobals.Symbols.GetImageSource(AppSymbols.software_installer));
|
|
||||||
}
|
|
||||||
void everythingOk()
|
|
||||||
{
|
|
||||||
SetStatus(GeneralLangRes.EverythingIsRightAndUpToDate, AppGlobals.Symbols.GetImageSource(AppSymbols.done));
|
|
||||||
currentUpdating = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check only if not pressed "install", not really needed otherwise.
|
|
||||||
if (lastUpdateCheckResult is null || !doInstall || repair)
|
|
||||||
{
|
|
||||||
SetStatus(GeneralLangRes.CheckingForUpdates, AppGlobals.Symbols.GetImageSource(AppSymbols.update_done));
|
|
||||||
|
|
||||||
// Check for extras once again
|
|
||||||
updateOptions.IncludeExtras = AllowExtras();
|
|
||||||
|
|
||||||
// Force re-install on repair
|
|
||||||
updateOptions.IgnoreInstalledVersion = repair;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
lastUpdateCheckResult = await updater.Check(updateOptions);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
error();
|
|
||||||
if (Debugger.IsAttached)
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Error while update check
|
|
||||||
if (lastUpdateCheckResult is null || lastUpdateCheckResult.HasError)
|
|
||||||
{
|
|
||||||
error();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load options
|
|
||||||
// lastUpdateCheckResult.OptionsAvailable...
|
|
||||||
// lastUpdateCheckResult.OptionsEnabled...
|
|
||||||
|
|
||||||
// No updates available
|
|
||||||
if (!lastUpdateCheckResult.HasUpdates)
|
|
||||||
{
|
|
||||||
everythingOk();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Updates available (but don't install)
|
|
||||||
if (!doInstall)
|
|
||||||
{
|
|
||||||
updatesAvailable();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Install updates
|
|
||||||
installing();
|
|
||||||
currentUpdating = true;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// Install
|
|
||||||
if (await updater.Install(lastUpdateCheckResult) == false)
|
|
||||||
{
|
|
||||||
error();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Success
|
|
||||||
lastUpdateCheckResult = null; // Reset last update check, a new one would be needed now.
|
|
||||||
everythingOk();
|
|
||||||
}
|
|
||||||
catch (Exception)
|
|
||||||
{
|
|
||||||
// Error
|
|
||||||
error();
|
|
||||||
if (Debugger.IsAttached)
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool AllowExtras()
|
|
||||||
{
|
|
||||||
return features != null && features.IsEnabled(ModpackFeatures.FeatureAllowExtas, new AllowExtrasFeatureContext(modpackInfo));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Updated_CheckingProgresssUpdated(int toCheck, int processed)
|
|
||||||
{
|
|
||||||
SetStatus(Math.Round(processed / (double)toCheck * 100d, 1) + "%", AppGlobals.Symbols.GetImageSource(AppSymbols.update_done));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Update_InstallProgessUpdated(UpdateCheckResult result, int processedSyncs)
|
|
||||||
{
|
|
||||||
var actionCount = result.Actions.Count;
|
|
||||||
SetStatus(Math.Round(processedSyncs / (double)actionCount * 100d, 1) + "%", AppGlobals.Symbols.GetImageSource(AppSymbols.software_installer));
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Gui
|
|
||||||
|
|
||||||
private void MainForm_Closing(object? sender, WindowClosingEventArgs e)
|
|
||||||
{
|
|
||||||
AppConfig.Instance.LastMinecraftProfilePath = TextBoxMinecraftProfileFolder.Text?.Trim();
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void MainForm_Loaded(object? sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
var updates = new AppUpdates(Program.UpdateUrl, this);
|
|
||||||
updates.OnDownloadProgramUpdate += (o, _) => SetStatus(GeneralLangRes.DownloadProgramUpdate, AppGlobals.Symbols.GetImageSource(AppSymbols.software_installer));
|
|
||||||
await updates.UpdateApp();
|
|
||||||
ClearStatus();
|
|
||||||
|
|
||||||
CheckStatusAndUpdate(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TextBoxMinecraftProfileFolder_TextChanged(object? o, TextChangedEventArgs args)
|
|
||||||
{
|
|
||||||
if (!loadingData)
|
|
||||||
CheckStatusAndUpdate(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TextBoxModpackConfig_TextChanged(object? o, RoutedEventArgs args)
|
|
||||||
{
|
|
||||||
if (!loadingData)
|
|
||||||
CheckStatusAndUpdate(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void TextBoxInstallKey_TextChanged(object? o, RoutedEventArgs args)
|
|
||||||
{
|
|
||||||
if (!loadingData)
|
|
||||||
CheckStatusAndUpdate(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
|
||||||
TextBoxMinecraftProfileFolder.Text = filePaths[0].Path.AbsolutePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void ButtonCheckForUpdates_Click(object? sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
ClearStatus();
|
|
||||||
await ExecuteUpdate(false, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void ButtonInstall_Click(object? sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (currentUpdating)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ClearStatus();
|
|
||||||
await ExecuteUpdate(true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
private async void MenuItemRepair_Click(object? sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (currentUpdating)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ClearStatus();
|
|
||||||
await ExecuteUpdate(true, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
@@ -4,15 +4,23 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:lang="clr-namespace:ModpackUpdater.Apps.Client.Gui.LangRes"
|
xmlns:lang="clr-namespace:ModpackUpdater.Apps.Client.Gui.LangRes"
|
||||||
xmlns:pilz="https://git.pilzinsel64.de/pilz-framework/pilz"
|
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"
|
xmlns:symbols="clr-namespace:Pilz.UI.Symbols;assembly=Pilz.UI"
|
||||||
mc:Ignorable="d"
|
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"
|
Width="520"
|
||||||
SizeToContent="Height"
|
SizeToContent="Height"
|
||||||
WindowStartupLocation="CenterScreen"
|
WindowStartupLocation="CenterScreen"
|
||||||
CanMaximize="false"
|
CanMaximize="false"
|
||||||
Title="Minecraft Modpack Updater"
|
Title="Minecraft Modpack Updater"
|
||||||
Icon="/Assets/app.ico">
|
Icon="/Assets/app.ico"
|
||||||
|
Loaded="Control_OnLoaded">
|
||||||
|
|
||||||
|
<Design.DataContext>
|
||||||
|
<gui:MainViewModel/>
|
||||||
|
</Design.DataContext>
|
||||||
|
|
||||||
<Grid
|
<Grid
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto"
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto"
|
||||||
@@ -21,6 +29,13 @@
|
|||||||
Margin="3"
|
Margin="3"
|
||||||
x:Name="MainGrid">
|
x:Name="MainGrid">
|
||||||
|
|
||||||
|
<Grid.IsEnabled>
|
||||||
|
<MultiBinding Converter="{x:Static BoolConverters.And}">
|
||||||
|
<Binding Path="HasInitialized"/>
|
||||||
|
<Binding Path="!IsUpdating"/>
|
||||||
|
</MultiBinding>
|
||||||
|
</Grid.IsEnabled>
|
||||||
|
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto"/>
|
<ColumnDefinition Width="Auto"/>
|
||||||
<ColumnDefinition Width="*" MinWidth="250"/>
|
<ColumnDefinition Width="*" MinWidth="250"/>
|
||||||
@@ -30,11 +45,11 @@
|
|||||||
<!-- Labels -->
|
<!-- Labels -->
|
||||||
<Label Grid.Row="0" Grid.Column="0" Margin="3" Content="{x:Static lang:GeneralLangRes.MinecraftProfile}" Target="TextBoxMinecraftProfileFolder"/>
|
<Label Grid.Row="0" Grid.Column="0" Margin="3" Content="{x:Static lang:GeneralLangRes.MinecraftProfile}" Target="TextBoxMinecraftProfileFolder"/>
|
||||||
<Label Grid.Row="1" Grid.Column="0" Margin="3" Content="{x:Static lang:GeneralLangRes.ModpackConfigUrl}" Target="TextBoxModpackConfig"/>
|
<Label Grid.Row="1" Grid.Column="0" Margin="3" Content="{x:Static lang:GeneralLangRes.ModpackConfigUrl}" Target="TextBoxModpackConfig"/>
|
||||||
<Label Grid.Row="2" Grid.Column="0" Margin="3" IsVisible="false" x:Name="LabelInstallKey" Content="{x:Static lang:GeneralLangRes.InstallationKey}" Target="TextBoxInstallKey"/>
|
<Label Grid.Row="2" Grid.Column="0" Margin="3" IsVisible="{Binding CanUseExtrasKey}" Content="{x:Static lang:GeneralLangRes.InstallationKey}" Target="TextBoxInstallKey"/>
|
||||||
<TextBlock Grid.Row="3" Grid.Column="0" Margin="3" Text="{x:Static lang:GeneralLangRes.Status}"/>
|
<TextBlock Grid.Row="3" Grid.Column="0" Margin="3" Text="{x:Static lang:GeneralLangRes.Status}"/>
|
||||||
<StackPanel Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2" Margin="3" Orientation="Horizontal" Spacing="6" MinHeight="{Binding MinHeight, ElementName=TextBoxMinecraftProfileFolder}">
|
<StackPanel Grid.Row="3" Grid.Column="1" Grid.ColumnSpan="2" Margin="3" Orientation="Horizontal" Spacing="6" MinHeight="{Binding MinHeight, ElementName=TextBoxMinecraftProfileFolder}">
|
||||||
<Image Width="{x:Static symbols:SymbolGlobals.DefaultImageSmallSize}" x:Name="ImageStatus"/>
|
<Image Width="{x:Static symbols:SymbolGlobals.DefaultImageSmallSize}" Source="{Binding StatusImage}"/>
|
||||||
<TextBlock x:Name="TextStatus"/>
|
<TextBlock Text="{Binding StatusText}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<!-- TextBoxes: Profile -->
|
<!-- TextBoxes: Profile -->
|
||||||
@@ -45,7 +60,7 @@
|
|||||||
Margin="3"
|
Margin="3"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Watermark="C:\..."
|
Watermark="C:\..."
|
||||||
TextChanged="TextBoxMinecraftProfileFolder_TextChanged"/>
|
Text="{Binding MinecraftProfileFolder}"/>
|
||||||
|
|
||||||
<!-- TextBoxes: ModpackConfig -->
|
<!-- TextBoxes: ModpackConfig -->
|
||||||
<TextBox
|
<TextBox
|
||||||
@@ -56,7 +71,7 @@
|
|||||||
Margin="3"
|
Margin="3"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Watermark="https://..."
|
Watermark="https://..."
|
||||||
TextChanged="TextBoxModpackConfig_TextChanged"/>
|
Text="{Binding ModpackConfigUrl}"/>
|
||||||
|
|
||||||
<!-- TextBoxes: InstallKey -->
|
<!-- TextBoxes: InstallKey -->
|
||||||
<TextBox
|
<TextBox
|
||||||
@@ -67,11 +82,11 @@
|
|||||||
Margin="3"
|
Margin="3"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Watermark="XXXXX-YYYYY-ZZZZZ-AAAAA-BBBBB"
|
Watermark="XXXXX-YYYYY-ZZZZZ-AAAAA-BBBBB"
|
||||||
TextChanged="TextBoxInstallKey_TextChanged"
|
Text="{Binding InstallKey}"
|
||||||
IsVisible="false"/>
|
IsVisible="{Binding CanUseExtrasKey}"/>
|
||||||
|
|
||||||
<!-- Button: SearchProfileFolder -->
|
<!-- Button: SearchProfileFolder -->
|
||||||
<pilz:ImageButton
|
<pilz:ImageSplitButton
|
||||||
x:Name="ButtonSearchProfileFolder"
|
x:Name="ButtonSearchProfileFolder"
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Grid.Column="2"
|
Grid.Column="2"
|
||||||
@@ -79,7 +94,28 @@
|
|||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Text="{x:Static lang:GeneralLangRes.Select}"
|
Text="{x:Static lang:GeneralLangRes.Select}"
|
||||||
Click="ButtonSearchProfileFolder_Click"/>
|
Click="ButtonSearchProfileFolder_Click">
|
||||||
|
|
||||||
|
<pilz:ImageSplitButton.DataTemplates>
|
||||||
|
<DataTemplate DataType="gui:MainViewModel+EmptyRecentFilesItem">
|
||||||
|
<TextBlock Text="{x:Static lang:GeneralLangRes.NoRecentProfilesAvailable}" FontStyle="Italic"/>
|
||||||
|
</DataTemplate>
|
||||||
|
|
||||||
|
<DataTemplate DataType="gui:MainViewModel+RecentFilesItem">
|
||||||
|
<MenuItem Header="{Binding Display}" Command="{Binding DataContext.OpenRecentPathCommand, ElementName=window}" CommandParameter="{Binding Path}" />
|
||||||
|
</DataTemplate>
|
||||||
|
</pilz:ImageSplitButton.DataTemplates>
|
||||||
|
|
||||||
|
<pilz:ImageSplitButton.Flyout>
|
||||||
|
<MenuFlyout ItemsSource="{Binding RecentMinecraftProfilePathItems}">
|
||||||
|
<MenuFlyout.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<ContentControl Content="{Binding}"/>
|
||||||
|
</DataTemplate>
|
||||||
|
</MenuFlyout.ItemTemplate>
|
||||||
|
</MenuFlyout>
|
||||||
|
</pilz:ImageSplitButton.Flyout>
|
||||||
|
</pilz:ImageSplitButton>
|
||||||
|
|
||||||
<!-- Button: CheckForUpdates -->
|
<!-- Button: CheckForUpdates -->
|
||||||
<pilz:ImageButton
|
<pilz:ImageButton
|
||||||
@@ -90,7 +126,8 @@
|
|||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
Text="{x:Static lang:GeneralLangRes.CheckForUpdates}"
|
Text="{x:Static lang:GeneralLangRes.CheckForUpdates}"
|
||||||
Click="ButtonCheckForUpdates_Click"/>
|
Command="{Binding CheckForUpdatesCommand}"
|
||||||
|
IsEnabled="{Binding CanUpdate}"/>
|
||||||
|
|
||||||
<!-- Button: Install -->
|
<!-- Button: Install -->
|
||||||
<pilz:ImageSplitButton
|
<pilz:ImageSplitButton
|
||||||
@@ -102,10 +139,12 @@
|
|||||||
HorizontalAlignment="Stretch"
|
HorizontalAlignment="Stretch"
|
||||||
HorizontalContentAlignment="Center"
|
HorizontalContentAlignment="Center"
|
||||||
Text="{x:Static lang:GeneralLangRes.Install}"
|
Text="{x:Static lang:GeneralLangRes.Install}"
|
||||||
Click="ButtonInstall_Click">
|
Command="{Binding InstallCommand}"
|
||||||
|
IsEnabled="{Binding CanUpdate}">
|
||||||
|
|
||||||
<SplitButton.Flyout>
|
<SplitButton.Flyout>
|
||||||
<MenuFlyout>
|
<MenuFlyout>
|
||||||
<MenuItem x:Name="MenuItemRepair" Header="{x:Static lang:GeneralLangRes.Repair}" Click="MenuItemRepair_Click"/>
|
<MenuItem x:Name="MenuItemRepair" Header="{x:Static lang:GeneralLangRes.Repair}" Command="{Binding RepairCommand}"/>
|
||||||
</MenuFlyout>
|
</MenuFlyout>
|
||||||
</SplitButton.Flyout>
|
</SplitButton.Flyout>
|
||||||
</pilz:ImageSplitButton>
|
</pilz:ImageSplitButton>
|
||||||
51
ModpackUpdater.Apps.Client.Gui/MainView.axaml.cs
Normal file
51
ModpackUpdater.Apps.Client.Gui/MainView.axaml.cs
Normal file
@@ -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().ToShortHumanString()})";
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
340
ModpackUpdater.Apps.Client.Gui/MainViewModel.cs
Normal file
340
ModpackUpdater.Apps.Client.Gui/MainViewModel.cs
Normal file
@@ -0,0 +1,340 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Windows.Input;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Media;
|
||||||
|
using CommunityToolkit.Mvvm.ComponentModel;
|
||||||
|
using CommunityToolkit.Mvvm.Input;
|
||||||
|
using ModpackUpdater.Apps.Client.Gui.LangRes;
|
||||||
|
using ModpackUpdater.Manager;
|
||||||
|
using Pilz.Extensions.Collections;
|
||||||
|
|
||||||
|
namespace ModpackUpdater.Apps.Client.Gui;
|
||||||
|
|
||||||
|
public partial class MainViewModel : ObservableObject
|
||||||
|
{
|
||||||
|
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 UpdateCheckResult? lastUpdateCheckResult;
|
||||||
|
|
||||||
|
[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 ObservableCollection<object> RecentMinecraftProfilePathItems { get; } = [];
|
||||||
|
|
||||||
|
public ICommand CheckForUpdatesCommand { get; }
|
||||||
|
public ICommand InstallCommand { get; }
|
||||||
|
public ICommand RepairCommand { get; }
|
||||||
|
|
||||||
|
public MainViewModel()
|
||||||
|
{
|
||||||
|
CheckForUpdatesCommand = new AsyncRelayCommand(async () => await CheckStatusAndUpdate(false));
|
||||||
|
InstallCommand = new AsyncRelayCommand(async () => await ExecuteUpdate(true, false));
|
||||||
|
RepairCommand = new AsyncRelayCommand(async () => await ExecuteUpdate(true, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CheckForUpdates(Window parent)
|
||||||
|
{
|
||||||
|
var updates = new AppUpdates("client", parent);
|
||||||
|
updates.OnDownloadProgramUpdate += (_, _) => SetStatus(GeneralLangRes.DownloadProgramUpdate, AppGlobals.Symbols.GetImageSource(AppSymbols.software_installer));
|
||||||
|
await updates.UpdateApp();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task Initialize()
|
||||||
|
{
|
||||||
|
ClearStatus();
|
||||||
|
LoadProfileToUi();
|
||||||
|
LoadRecentFilesToUi();
|
||||||
|
HasInitialized = true;
|
||||||
|
await CheckStatusAndUpdate(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnMinecraftProfileFolderChanged(string? value)
|
||||||
|
{
|
||||||
|
if (!LoadingData)
|
||||||
|
_ = CheckStatusAndUpdate(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnModpackConfigUrlChanged(string? value)
|
||||||
|
{
|
||||||
|
if (!LoadingData)
|
||||||
|
_ = CheckStatusAndUpdate(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
partial void OnInstallKeyChanged(string? value)
|
||||||
|
{
|
||||||
|
if (!LoadingData)
|
||||||
|
_ = CheckStatusAndUpdate(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SetStatus(string statusText, IImage? image)
|
||||||
|
{
|
||||||
|
StatusText = statusText;
|
||||||
|
StatusImage = image;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ClearStatus()
|
||||||
|
{
|
||||||
|
StatusText = "-";
|
||||||
|
StatusImage = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool AllowExtras()
|
||||||
|
{
|
||||||
|
return !string.IsNullOrWhiteSpace(modpackInfo.ExtrasKey) && updateConfig.ExtrasKeys.Contains(modpackInfo.ExtrasKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadProfileToUi()
|
||||||
|
{
|
||||||
|
LoadingData = true;
|
||||||
|
|
||||||
|
MinecraftProfileFolder = modpackInfo.LocalPath ?? AppConfig.Instance.RecentMinecraftProfilePaths.FirstOrDefault() ?? MinecraftProfileFolder;
|
||||||
|
ModpackConfigUrl = modpackInfo.ConfigUrl ?? ModpackConfigUrl;
|
||||||
|
InstallKey = modpackInfo.ExtrasKey ?? InstallKey;
|
||||||
|
|
||||||
|
LoadingData = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadOptionsToUi()
|
||||||
|
{
|
||||||
|
//foreach (var set in )
|
||||||
|
//{
|
||||||
|
// // ...
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void LoadRecentFilesToUi()
|
||||||
|
{
|
||||||
|
RecentMinecraftProfilePathItems.Clear();
|
||||||
|
|
||||||
|
if (AppConfig.Instance.RecentMinecraftProfilePaths.Count == 0)
|
||||||
|
{
|
||||||
|
RecentMinecraftProfilePathItems.Add(new EmptyRecentFilesItem());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppConfig.Instance.RecentMinecraftProfilePaths.ForEach(path =>
|
||||||
|
{
|
||||||
|
if (Directory.Exists(path))
|
||||||
|
RecentMinecraftProfilePathItems.Add(new RecentFilesItem(path));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void StoreRecentMinecraftProfilePath(string? path)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrWhiteSpace(path))
|
||||||
|
return;
|
||||||
|
|
||||||
|
AppConfig.Instance.RecentMinecraftProfilePaths.RemoveAll(n => n == path);
|
||||||
|
AppConfig.Instance.RecentMinecraftProfilePaths.Insert(0, path);
|
||||||
|
AppConfig.Instance.RecentMinecraftProfilePaths.Skip(10).ForEach(n => AppConfig.Instance.RecentMinecraftProfilePaths.Remove(n));
|
||||||
|
}
|
||||||
|
|
||||||
|
[RelayCommand]
|
||||||
|
private void OpenRecentPath(string path)
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(path))
|
||||||
|
MinecraftProfileFolder = path;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task CheckStatusAndUpdate(bool loadProfileToUi)
|
||||||
|
{
|
||||||
|
if (!CheckStatus(loadProfileToUi))
|
||||||
|
return;
|
||||||
|
|
||||||
|
await ExecuteUpdate(false, false);
|
||||||
|
|
||||||
|
StoreRecentMinecraftProfilePath(modpackInfo.LocalPath);
|
||||||
|
LoadRecentFilesToUi();
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool CheckStatus(bool loadProfileToUi)
|
||||||
|
{
|
||||||
|
ClearStatus();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
modpackInfo = ModpackInfo.TryLoad(MinecraftProfileFolder?.Trim());
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loadProfileToUi)
|
||||||
|
LoadProfileToUi();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
updateConfig = ModpackConfig.LoadFromUrl(ModpackConfigUrl);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
modpackInfo.ExtrasKey = InstallKey?.Trim();
|
||||||
|
if (!string.IsNullOrWhiteSpace(modpackInfo.ExtrasKey) && !AllowExtras())
|
||||||
|
{
|
||||||
|
SetStatus(GeneralLangRes.InstallationKeyNotValid, AppGlobals.Symbols.GetImageSource(AppSymbols.general_warning_sign));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
CanUseExtrasKey = updateConfig.ExtrasKeys.Count > 0;
|
||||||
|
|
||||||
|
if (string.IsNullOrWhiteSpace(MinecraftProfileFolder) /*|| modpackInfo.Valid*/)
|
||||||
|
{
|
||||||
|
SetStatus(GeneralLangRes.MinecraftProfileFolderSeemsInvalid, AppGlobals.Symbols.GetImageSource(AppSymbols.general_warning_sign));
|
||||||
|
CanUpdate = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (string.IsNullOrWhiteSpace(ModpackConfigUrl))
|
||||||
|
{
|
||||||
|
SetStatus(GeneralLangRes.ConfigIncompleteOrNotLoaded, AppGlobals.Symbols.GetImageSource(AppSymbols.general_warning_sign));
|
||||||
|
CanUpdate = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (updateConfig.Maintenance && !updateOptions.IgnoreMaintenance)
|
||||||
|
{
|
||||||
|
SetStatus(GeneralLangRes.UpdateServerInMaintenance, AppGlobals.Symbols.GetImageSource(AppSymbols.services));
|
||||||
|
CanUpdate = false;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
LoadOptionsToUi();
|
||||||
|
CanUpdate = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task ExecuteUpdate(bool doInstall, bool repair)
|
||||||
|
{
|
||||||
|
ClearStatus();
|
||||||
|
|
||||||
|
// Ensure set extras key
|
||||||
|
modpackInfo.ExtrasKey = InstallKey?.Trim();
|
||||||
|
|
||||||
|
var updater = new ModpackInstaller(updateConfig, modpackInfo);
|
||||||
|
updater.InstallProgessUpdated += Updater_InstallProgressUpdated;
|
||||||
|
updater.CheckingProgressUpdated += Updater_CheckingProgressUpdated;
|
||||||
|
|
||||||
|
void error()
|
||||||
|
{
|
||||||
|
SetStatus(GeneralLangRes.ErrorOnUpdateCheckOrUpdating, AppGlobals.Symbols.GetImageSource(AppSymbols.close));
|
||||||
|
IsUpdating = false;
|
||||||
|
}
|
||||||
|
void installing()
|
||||||
|
{
|
||||||
|
SetStatus(GeneralLangRes.Installing, AppGlobals.Symbols.GetImageSource(AppSymbols.software_installer));
|
||||||
|
IsUpdating = true;
|
||||||
|
}
|
||||||
|
void updatesAvailable()
|
||||||
|
{
|
||||||
|
SetStatus(GeneralLangRes.AnUpdateIsAvailable, AppGlobals.Symbols.GetImageSource(AppSymbols.software_installer));
|
||||||
|
IsUpdating = false;
|
||||||
|
}
|
||||||
|
void everythingOk()
|
||||||
|
{
|
||||||
|
SetStatus(GeneralLangRes.EverythingIsRightAndUpToDate, AppGlobals.Symbols.GetImageSource(AppSymbols.done));
|
||||||
|
IsUpdating = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check only if not pressed "install", not really needed otherwise.
|
||||||
|
if (lastUpdateCheckResult is null || !doInstall || repair)
|
||||||
|
{
|
||||||
|
SetStatus(GeneralLangRes.CheckingForUpdates, AppGlobals.Symbols.GetImageSource(AppSymbols.update_done));
|
||||||
|
|
||||||
|
// Check for extras once again
|
||||||
|
updateOptions.IncludeExtras = AllowExtras();
|
||||||
|
|
||||||
|
// Force re-install on repair
|
||||||
|
updateOptions.IgnoreInstalledVersion = repair;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
lastUpdateCheckResult = await updater.Check(updateOptions);
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
error();
|
||||||
|
if (Debugger.IsAttached)
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error while update check
|
||||||
|
if (lastUpdateCheckResult is null || lastUpdateCheckResult.HasError)
|
||||||
|
{
|
||||||
|
error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load options
|
||||||
|
// lastUpdateCheckResult.OptionsAvailable...
|
||||||
|
// lastUpdateCheckResult.OptionsEnabled...
|
||||||
|
|
||||||
|
// No updates available
|
||||||
|
if (!lastUpdateCheckResult.HasUpdates)
|
||||||
|
{
|
||||||
|
everythingOk();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Updates available (but don't install)
|
||||||
|
if (!doInstall)
|
||||||
|
{
|
||||||
|
updatesAvailable();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Install updates
|
||||||
|
installing();
|
||||||
|
IsUpdating = true;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// Install
|
||||||
|
if (await updater.Install(lastUpdateCheckResult) == false)
|
||||||
|
{
|
||||||
|
error();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Success
|
||||||
|
lastUpdateCheckResult = null; // Reset last update check, a new one would be needed now.
|
||||||
|
everythingOk();
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
// Error
|
||||||
|
error();
|
||||||
|
if (Debugger.IsAttached)
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Updater_CheckingProgressUpdated(int toCheck, int processed)
|
||||||
|
{
|
||||||
|
SetStatus(Math.Round(processed / (double)toCheck * 100d, 1) + "%", AppGlobals.Symbols.GetImageSource(AppSymbols.update_done));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Updater_InstallProgressUpdated(UpdateCheckResult result, int processedSyncs)
|
||||||
|
{
|
||||||
|
var actionCount = result.Actions.Count;
|
||||||
|
SetStatus(Math.Round(processedSyncs / (double)actionCount * 100d, 1) + "%", AppGlobals.Symbols.GetImageSource(AppSymbols.software_installer));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -66,27 +66,28 @@
|
|||||||
<PrivateAssets>all</PrivateAssets>
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="MessageBox.Avalonia" Version="3.3.0" />
|
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.4.0" />
|
||||||
|
<PackageReference Include="MessageBox.Avalonia" Version="3.3.1" />
|
||||||
<PackageReference Include="Mono.Options" Version="6.12.0.148" />
|
<PackageReference Include="Mono.Options" Version="6.12.0.148" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||||
<PackageReference Include="Pilz" Version="2.6.1" />
|
<PackageReference Include="Pilz" Version="2.7.8" />
|
||||||
<PackageReference Include="Pilz.Configuration" Version="3.2.7" />
|
<PackageReference Include="Pilz.Configuration" Version="3.2.8" />
|
||||||
<PackageReference Include="Pilz.Cryptography" Version="2.1.2" />
|
<PackageReference Include="Pilz.Cryptography" Version="2.1.3" />
|
||||||
<PackageReference Include="Pilz.IO" Version="2.1.0" />
|
<PackageReference Include="Pilz.IO" Version="2.1.1" />
|
||||||
<PackageReference Include="Pilz.UI" Version="3.1.4" />
|
<PackageReference Include="Pilz.UI" Version="3.1.5" />
|
||||||
<PackageReference Include="Pilz.UI.AvaloniaUI" Version="1.2.18" />
|
<PackageReference Include="Pilz.UI.AvaloniaUI" Version="1.2.21" />
|
||||||
<PackageReference Include="Avalonia" Version="11.3.8" />
|
<PackageReference Include="Avalonia" Version="11.3.10" />
|
||||||
<PackageReference Include="Avalonia.Desktop" Version="11.3.8" />
|
<PackageReference Include="Avalonia.Desktop" Version="11.3.10" />
|
||||||
<PackageReference Include="Avalonia.Svg" Version="11.3.0" />
|
<PackageReference Include="Avalonia.Svg" Version="11.3.0" />
|
||||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.3.8" />
|
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.3.10" />
|
||||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.3.8" />
|
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.3.10" />
|
||||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
||||||
<PackageReference Include="Avalonia.Diagnostics" Version="11.3.8">
|
<PackageReference Include="Avalonia.Diagnostics" Version="11.3.10">
|
||||||
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
|
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
|
||||||
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Pilz.Updating" Version="4.3.5" />
|
<PackageReference Include="Pilz.Updating" Version="4.3.6" />
|
||||||
<PackageReference Include="Pilz.Updating.Client" Version="4.4.6" />
|
<PackageReference Include="Pilz.Updating.Client" Version="4.4.8" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ namespace ModpackUpdater.Apps.Client.Gui;
|
|||||||
|
|
||||||
public static class Program
|
public static class Program
|
||||||
{
|
{
|
||||||
public const string UpdateUrl = "https://git.pilzinsel64.de/litw-refined/minecraft-modpack-updater/-/snippets/3/raw/main/updates-new.json";
|
|
||||||
|
|
||||||
private static readonly SettingsManager settingsManager;
|
private static readonly SettingsManager settingsManager;
|
||||||
|
|
||||||
public static ISettings Settings => settingsManager.Instance;
|
public static ISettings Settings => settingsManager.Instance;
|
||||||
@@ -18,7 +16,6 @@ public static class Program
|
|||||||
static Program()
|
static Program()
|
||||||
{
|
{
|
||||||
settingsManager = new(GetSettingsPath(2), true);
|
settingsManager = new(GetSettingsPath(2), true);
|
||||||
MigrateLegacySettings(GetSettingsPath(null));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[STAThread]
|
[STAThread]
|
||||||
@@ -47,25 +44,4 @@ public static class Program
|
|||||||
|
|
||||||
return settingsPath;
|
return settingsPath;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void MigrateLegacySettings(string settingsPath)
|
|
||||||
{
|
|
||||||
// Try load legacy config file
|
|
||||||
if (!File.Exists(settingsPath) || JsonConvert.DeserializeObject<AppConfig>(File.ReadAllText(settingsPath)) is not AppConfig legacyConfig)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// Migrate
|
|
||||||
var newConfig = Settings.Get<AppConfig>();
|
|
||||||
newConfig.LastMinecraftProfilePath = legacyConfig.LastMinecraftProfilePath;
|
|
||||||
|
|
||||||
if (ModpackInfo.TryLoad(legacyConfig.LastMinecraftProfilePath) is ModpackInfo info)
|
|
||||||
#pragma warning disable CS0612 // Typ oder Element ist veraltet
|
|
||||||
info.ConfigUrl = legacyConfig.ConfigFilePath;
|
|
||||||
|
|
||||||
// Ensure save settings
|
|
||||||
settingsManager.Save();
|
|
||||||
|
|
||||||
// Delete legacy config file
|
|
||||||
File.Delete(settingsPath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
pupnet -y -v "$1[1]" -r linux-x64 -k appimage
|
|
||||||
#pupnet -y -v "$1[1]" -r linux-x64 -k flatpak -p DefineConstants=DISABLE_UPDATE
|
|
||||||
#pupnet -y -v "$1[1]"-r linux-x64 -k deb -p DefineConstants=DISABLE_UPDATE
|
|
||||||
#pupnet -y -v "$1[1]"-r linux-x64 -k rpm -p DefineConstants=DISABLE_UPDATE
|
|
||||||
pupnet -y -v "$1[1]" -r linux-arm64 -k appimage
|
|
||||||
#pupnet -y -v "$1[1]" -r linux-arm64 -k flatpak -p DefineConstants=DISABLE_UPDATE
|
|
||||||
#pupnet -y -v "$1[1]"-r linux-arm64 -k deb -p DefineConstants=DISABLE_UPDATE
|
|
||||||
#pupnet -y -v "$1[1]"-r linux-arm64 -k rpm -p DefineConstants=DISABLE_UPDATE
|
|
||||||
pupnet -y -v "$1[1]" -r win-x64 -k zip
|
|
||||||
pupnet -y -v "$1[1]" -r win-arm64 -k zip
|
|
||||||
pupnet -y -v "$1[1]" -r osx-x64 -k zip
|
|
||||||
pupnet -y -v "$1[1]" -r osx-arm64 -k zip
|
|
||||||
@@ -23,9 +23,9 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Mono.Options" Version="6.12.0.148" />
|
<PackageReference Include="Mono.Options" Version="6.12.0.148" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.4" />
|
||||||
<PackageReference Include="Pilz" Version="2.6.1" />
|
<PackageReference Include="Pilz" Version="2.7.8" />
|
||||||
<PackageReference Include="Pilz.Cryptography" Version="2.1.2" />
|
<PackageReference Include="Pilz.Cryptography" Version="2.1.3" />
|
||||||
<PackageReference Include="Pilz.IO" Version="2.1.0" />
|
<PackageReference Include="Pilz.IO" Version="2.1.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
using Castle.Core.Logging;
|
using System.Reflection;
|
||||||
|
using Castle.Core.Logging;
|
||||||
using ModpackUpdater.Manager;
|
using ModpackUpdater.Manager;
|
||||||
|
using Pilz.Extensions;
|
||||||
|
|
||||||
namespace ModpackUpdater.Apps.Client;
|
namespace ModpackUpdater.Apps.Client;
|
||||||
|
|
||||||
@@ -15,22 +17,34 @@ public static class Program
|
|||||||
{
|
{
|
||||||
Options = new Options(args);
|
Options = new Options(args);
|
||||||
if (Options.Help)
|
if (Options.Help)
|
||||||
|
{
|
||||||
|
DrawInfo();
|
||||||
Options.DrawHelp();
|
Options.DrawHelp();
|
||||||
else
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Options.Silent)
|
||||||
|
DrawInfo();
|
||||||
InstallWithoutGui(Options.UpdateOptions, Options.Silent);
|
InstallWithoutGui(Options.UpdateOptions, Options.Silent);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void DrawInfo()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Minecraft Modpack Updater CLI");
|
||||||
|
Console.WriteLine("Version " + Assembly.GetExecutingAssembly().GetAppVersion().ToShortHumanString());
|
||||||
|
Console.WriteLine("------------------------------");
|
||||||
|
}
|
||||||
|
|
||||||
private static void InstallWithoutGui(UpdateCheckOptionsAdv updateOptions, bool silent)
|
private static void InstallWithoutGui(UpdateCheckOptionsAdv updateOptions, bool silent)
|
||||||
{
|
{
|
||||||
var info = ModpackInfo.TryLoad(updateOptions.ProfileFolder);
|
var info = ModpackInfo.TryLoad(updateOptions.ProfileFolder);
|
||||||
var config = ModpackConfig.LoadFromUrl(CheckModpackConfigUrl(updateOptions.ModpackConfig!, info));
|
var config = ModpackConfig.LoadFromUrl(CheckModpackConfigUrl(updateOptions.ModpackConfig!, info));
|
||||||
var features = new ModpackFeatures(config);
|
|
||||||
|
|
||||||
// Check features
|
// Check features
|
||||||
if (!string.IsNullOrWhiteSpace(updateOptions.ExtrasKey))
|
if (!string.IsNullOrWhiteSpace(updateOptions.ExtrasKey))
|
||||||
info.ExtrasKey = updateOptions.ExtrasKey;
|
info.ExtrasKey = updateOptions.ExtrasKey;
|
||||||
if (!string.IsNullOrWhiteSpace(info.ExtrasKey))
|
if (!string.IsNullOrWhiteSpace(info.ExtrasKey))
|
||||||
updateOptions.IncludeExtras = features.IsEnabled(ModpackFeatures.FeatureAllowExtas, new AllowExtrasFeatureContext(info));
|
updateOptions.IncludeExtras = !string.IsNullOrWhiteSpace(info.ExtrasKey) && config.ExtrasKeys.Contains(info.ExtrasKey);
|
||||||
|
|
||||||
// Check for update
|
// Check for update
|
||||||
var installer = new ModpackInstaller(config, info)
|
var installer = new ModpackInstaller(config, info)
|
||||||
|
|||||||
@@ -1,12 +0,0 @@
|
|||||||
pupnet -y -v "$1[1]" -r linux-x64 -k appimage
|
|
||||||
#pupnet -y -v "$1[1]" -r linux-x64 -k flatpak
|
|
||||||
#pupnet -y -v "$1[1]"-r linux-x64 -k deb
|
|
||||||
#pupnet -y -v "$1[1]"-r linux-x64 -k rpm
|
|
||||||
pupnet -y -v "$1[1]" -r linux-arm64 -k appimage
|
|
||||||
#pupnet -y -v "$1[1]" -r linux-arm64 -k flatpak
|
|
||||||
#pupnet -y -v "$1[1]"-r linux-arm64 -k deb
|
|
||||||
#pupnet -y -v "$1[1]"-r linux-arm64 -k rpm
|
|
||||||
pupnet -y -v "$1[1]" -r win-x64 -k zip
|
|
||||||
pupnet -y -v "$1[1]" -r win-arm64 -k zip
|
|
||||||
pupnet -y -v "$1[1]" -r osx-x64 -k zip
|
|
||||||
pupnet -y -v "$1[1]" -r osx-arm64 -k zip
|
|
||||||
@@ -70,7 +70,7 @@ internal static class SharedFunctions
|
|||||||
foreach (var update in updates)
|
foreach (var update in updates)
|
||||||
{
|
{
|
||||||
var sourceTag = update.AvailableVersions[update.NewVersion].Tag;
|
var sourceTag = update.AvailableVersions[update.NewVersion].Tag;
|
||||||
if (api.Model.CurrentGridRows?.FirstOrDefault(n => n.Action == update.Origin) is { } row)
|
if (api.Model.CurrentGridRows.List.Items.FirstOrDefault(n => n.Action == update.Origin) is { } row)
|
||||||
row.SourceTag = sourceTag;
|
row.SourceTag = sourceTag;
|
||||||
else
|
else
|
||||||
update.Origin.SourceTag = sourceTag;
|
update.Origin.SourceTag = sourceTag;
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ internal class CheckAllActionsHealthyFeature : PluginFunction, IPluginFeaturePro
|
|||||||
|
|
||||||
protected override async Task<object?> ExecuteFunctionAsync(PluginFunctionParameter? @params)
|
protected override async Task<object?> ExecuteFunctionAsync(PluginFunctionParameter? @params)
|
||||||
{
|
{
|
||||||
if (@params is not MainApiParameters p || p.Api.Model.CurrentGridRows is null)
|
if (@params is not MainApiParameters p)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
await SharedFunctions.CheckActionHealthy(p.Api, [.. p.Api.Model.CurrentGridRows]);
|
await SharedFunctions.CheckActionHealthy(p.Api, [.. p.Api.Model.CurrentGridRows.View]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ internal class ClearDirectLinksFeature : PluginFunction, IPluginFeatureProvider<
|
|||||||
|
|
||||||
protected override Task<object?> ExecuteFunctionAsync(PluginFunctionParameter? @params)
|
protected override Task<object?> ExecuteFunctionAsync(PluginFunctionParameter? @params)
|
||||||
{
|
{
|
||||||
if (@params is MainApiParameters p && p.Api.Model.CurrentGridRows is not null)
|
if (@params is MainApiParameters p)
|
||||||
SharedFunctions.ClearDirectLinks(p.Api, [.. p.Api.Model.CurrentGridRows]);
|
SharedFunctions.ClearDirectLinks(p.Api, [.. p.Api.Model.CurrentGridRows.View]);
|
||||||
return Task.FromResult<object?>(null);
|
return Task.FromResult<object?>(null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ internal class UpdateDirectLinksFeature : PluginFunction, IPluginFeatureProvider
|
|||||||
|
|
||||||
protected override async Task<object?> ExecuteFunctionAsync(PluginFunctionParameter? @params)
|
protected override async Task<object?> ExecuteFunctionAsync(PluginFunctionParameter? @params)
|
||||||
{
|
{
|
||||||
if (@params is not MainApiParameters p || p.Api.Model.CurrentGridRows is null)
|
if (@params is not MainApiParameters p)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
await SharedFunctions.FindNewDirectLinks(p.Api, [.. p.Api.Model.CurrentGridRows]);
|
await SharedFunctions.FindNewDirectLinks(p.Api, [.. p.Api.Model.CurrentGridRows.View]);
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -273,6 +273,12 @@ namespace ModpackUpdater.Apps.Manager.LangRes {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string SourceTag {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("SourceTag", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static string SourceRegex {
|
public static string SourceRegex {
|
||||||
get {
|
get {
|
||||||
return ResourceManager.GetString("SourceRegex", resourceCulture);
|
return ResourceManager.GetString("SourceRegex", resourceCulture);
|
||||||
@@ -314,5 +320,11 @@ namespace ModpackUpdater.Apps.Manager.LangRes {
|
|||||||
return ResourceManager.GetString("SelectRootFolder", resourceCulture);
|
return ResourceManager.GetString("SelectRootFolder", resourceCulture);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string Search {
|
||||||
|
get {
|
||||||
|
return ResourceManager.GetString("Search", resourceCulture);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -231,6 +231,9 @@
|
|||||||
<data name="SourceName" xml:space="preserve">
|
<data name="SourceName" xml:space="preserve">
|
||||||
<value>Source name</value>
|
<value>Source name</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="SourceTag" xml:space="preserve">
|
||||||
|
<value>Source tag</value>
|
||||||
|
</data>
|
||||||
<data name="SourceRegex" xml:space="preserve">
|
<data name="SourceRegex" xml:space="preserve">
|
||||||
<value>Source RegEx</value>
|
<value>Source RegEx</value>
|
||||||
</data>
|
</data>
|
||||||
@@ -252,4 +255,7 @@
|
|||||||
<data name="SelectRootFolder" xml:space="preserve">
|
<data name="SelectRootFolder" xml:space="preserve">
|
||||||
<value>Select root folder</value>
|
<value>Select root folder</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="Search" xml:space="preserve">
|
||||||
|
<value>Search</value>
|
||||||
|
</data>
|
||||||
</root>
|
</root>
|
||||||
@@ -49,24 +49,25 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.3.8" />
|
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.3.10" />
|
||||||
<PackageReference Include="MessageBox.Avalonia" Version="3.3.0" />
|
<PackageReference Include="DynamicData" Version="9.4.1" />
|
||||||
<PackageReference Include="EPPlus" Version="8.2.1" />
|
<PackageReference Include="MessageBox.Avalonia" Version="3.3.1" />
|
||||||
<PackageReference Include="NGitLab" Version="11.0.1" />
|
<PackageReference Include="EPPlus" Version="8.4.0" />
|
||||||
<PackageReference Include="Pilz" Version="2.6.1" />
|
<PackageReference Include="NGitLab" Version="11.1.0" />
|
||||||
<PackageReference Include="Pilz.Configuration" Version="3.2.7" />
|
<PackageReference Include="Pilz" Version="2.7.8" />
|
||||||
<PackageReference Include="Pilz.Cryptography" Version="2.1.2" />
|
<PackageReference Include="Pilz.Configuration" Version="3.2.8" />
|
||||||
<PackageReference Include="Pilz.Features" Version="2.13.0" />
|
<PackageReference Include="Pilz.Cryptography" Version="2.1.3" />
|
||||||
<PackageReference Include="Pilz.UI" Version="3.1.4" />
|
<PackageReference Include="Pilz.Features" Version="2.13.1" />
|
||||||
<PackageReference Include="Pilz.UI.AvaloniaUI" Version="1.2.18" />
|
<PackageReference Include="Pilz.UI" Version="3.1.5" />
|
||||||
<PackageReference Include="Pilz.UI.AvaloniaUI.Features" Version="1.0.1" />
|
<PackageReference Include="Pilz.UI.AvaloniaUI" Version="1.2.21" />
|
||||||
<PackageReference Include="Avalonia" Version="11.3.8" />
|
<PackageReference Include="Pilz.UI.AvaloniaUI.Features" Version="1.0.2" />
|
||||||
<PackageReference Include="Avalonia.Desktop" Version="11.3.8" />
|
<PackageReference Include="Avalonia" Version="11.3.10" />
|
||||||
|
<PackageReference Include="Avalonia.Desktop" Version="11.3.10" />
|
||||||
<PackageReference Include="Avalonia.Svg" Version="11.3.0" />
|
<PackageReference Include="Avalonia.Svg" Version="11.3.0" />
|
||||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.3.8" />
|
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.3.10" />
|
||||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.3.8" />
|
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.3.10" />
|
||||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
||||||
<PackageReference Include="Avalonia.Diagnostics" Version="11.3.8">
|
<PackageReference Include="Avalonia.Diagnostics" Version="11.3.10">
|
||||||
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
|
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
|
||||||
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
@@ -142,10 +143,4 @@
|
|||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<Reference Include="Pilz">
|
|
||||||
<HintPath>..\..\..\.nuget\packages\pilz\2.6.1\lib\net8.0\Pilz.dll</HintPath>
|
|
||||||
</Reference>
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -7,8 +7,6 @@ namespace ModpackUpdater.Apps.Manager;
|
|||||||
|
|
||||||
public static class Program
|
public static class Program
|
||||||
{
|
{
|
||||||
public const string UpdateUrl = "https://git.pilzinsel64.de/litw-refined/minecraft-modpack-updater/-/snippets/3/raw/main/updates-manager.json";
|
|
||||||
|
|
||||||
internal static readonly SettingsManager settingsManager;
|
internal static readonly SettingsManager settingsManager;
|
||||||
|
|
||||||
public static ISettings Settings => settingsManager.Instance;
|
public static ISettings Settings => settingsManager.Instance;
|
||||||
|
|||||||
@@ -3,12 +3,11 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
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:local="clr-namespace:ModpackUpdater.Apps.Manager.Ui"
|
|
||||||
xmlns:pilz="https://git.pilzinsel64.de/pilz-framework/pilz"
|
xmlns:pilz="https://git.pilzinsel64.de/pilz-framework/pilz"
|
||||||
xmlns:symbols="clr-namespace:Pilz.UI.Symbols;assembly=Pilz.UI"
|
xmlns:symbols="clr-namespace:Pilz.UI.Symbols;assembly=Pilz.UI"
|
||||||
xmlns:mainWindow="clr-namespace:ModpackUpdater.Apps.Manager.Ui.Models.MainWindow"
|
xmlns:mainWindow="clr-namespace:ModpackUpdater.Apps.Manager.Ui.Models.MainWindow"
|
||||||
xmlns:langRes="clr-namespace:ModpackUpdater.Apps.Manager.LangRes"
|
xmlns:langRes="clr-namespace:ModpackUpdater.Apps.Manager.LangRes"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="450"
|
||||||
x:Class="ModpackUpdater.Apps.Manager.Ui.MainWindow"
|
x:Class="ModpackUpdater.Apps.Manager.Ui.MainWindow"
|
||||||
Title="Minecraft Modpack Manager"
|
Title="Minecraft Modpack Manager"
|
||||||
WindowState="Maximized"
|
WindowState="Maximized"
|
||||||
@@ -25,54 +24,44 @@
|
|||||||
ColumnSpacing="6"
|
ColumnSpacing="6"
|
||||||
Margin="3">
|
Margin="3">
|
||||||
|
|
||||||
<!-- StackPanel: Workspace -->
|
<!-- Menu: Workspace -->
|
||||||
<StackPanel
|
<Menu
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
Grid.Row="0"
|
Grid.Row="0">
|
||||||
Orientation="Horizontal">
|
|
||||||
|
|
||||||
<!-- Button: Workspace -->
|
<Menu.Items>
|
||||||
<pilz:ImageButton
|
<!-- MenuItem: Workspace -->
|
||||||
x:Name="ButtonWorkspace"
|
<pilz:HeaderMenuItem
|
||||||
Text="{x:Static langRes:GeneralLangRes.Workspace}"
|
x:Name="MenuItemWorkspace"
|
||||||
Background="Transparent">
|
HeaderText="{x:Static langRes:GeneralLangRes.Workspace}">
|
||||||
|
|
||||||
<pilz:ImageButton.Flyout>
|
<pilz:HeaderMenuItem.Items>
|
||||||
<MenuFlyout>
|
|
||||||
<MenuFlyout.Items>
|
|
||||||
<MenuItem x:Name="MenuItemWorkspacePreferences" Header="{x:Static langRes:GeneralLangRes.WorkspacePreferences}" Click="MenuItemWorkspacePreferences_OnClick"/>
|
<MenuItem x:Name="MenuItemWorkspacePreferences" Header="{x:Static langRes:GeneralLangRes.WorkspacePreferences}" Click="MenuItemWorkspacePreferences_OnClick"/>
|
||||||
<MenuItem x:Name="MenuItemSaveWorkspace" Header="{x:Static langRes:GeneralLangRes.SaveWorkspace}" HotKey="Ctrl+S" Click="MenuItemSaveWorkspace_OnClick"/>
|
<MenuItem x:Name="MenuItemSaveWorkspace" Header="{x:Static langRes:GeneralLangRes.SaveWorkspace}" HotKey="Ctrl+S" Click="MenuItemSaveWorkspace_OnClick"/>
|
||||||
<Separator/>
|
<Separator/>
|
||||||
<MenuItem x:Name="MenuItemNewWorkspace" Header="{x:Static langRes:GeneralLangRes.NewWorkspace}"/>
|
<MenuItem x:Name="MenuItemNewWorkspace" Header="{x:Static langRes:GeneralLangRes.NewWorkspace}"/>
|
||||||
<Separator/>
|
<Separator/>
|
||||||
<MenuItem x:Name="MenuItemRecentWorkspaces" Header="{x:Static langRes:GeneralLangRes.RecentWorkspaces}"/>
|
<MenuItem x:Name="MenuItemRecentWorkspaces" Header="{x:Static langRes:GeneralLangRes.RecentWorkspaces}"/>
|
||||||
</MenuFlyout.Items>
|
</pilz:HeaderMenuItem.Items>
|
||||||
</MenuFlyout>
|
</pilz:HeaderMenuItem>
|
||||||
</pilz:ImageButton.Flyout>
|
|
||||||
</pilz:ImageButton>
|
|
||||||
|
|
||||||
<!-- Button: Update -->
|
<!-- MenuItem: Update -->
|
||||||
<pilz:ImageButton
|
<pilz:HeaderMenuItem
|
||||||
x:Name="ButtonUpdate"
|
x:Name="MenuItemUpdate"
|
||||||
Text="{x:Static langRes:GeneralLangRes.Update}"
|
HeaderText="{x:Static langRes:GeneralLangRes.Update}">
|
||||||
Background="Transparent">
|
|
||||||
|
|
||||||
<pilz:ImageButton.Flyout>
|
<pilz:HeaderMenuItem.Items>
|
||||||
<MenuFlyout>
|
|
||||||
<MenuFlyout.Items>
|
|
||||||
<MenuItem x:Name="MenuItemCreateUpdate" Header="{x:Static langRes:GeneralLangRes.CreateUpdate}" Click="MenuItemCreateUpdate_OnClick"/>
|
<MenuItem x:Name="MenuItemCreateUpdate" Header="{x:Static langRes:GeneralLangRes.CreateUpdate}" Click="MenuItemCreateUpdate_OnClick"/>
|
||||||
<MenuItem x:Name="MenuItemRemoveUpdate" Header="{x:Static langRes:GeneralLangRes.RemoveUpdate}" Click="MenuItemRemoveUpdate_OnClick"/>
|
<MenuItem x:Name="MenuItemRemoveUpdate" Header="{x:Static langRes:GeneralLangRes.RemoveUpdate}" Click="MenuItemRemoveUpdate_OnClick"/>
|
||||||
</MenuFlyout.Items>
|
</pilz:HeaderMenuItem.Items>
|
||||||
</MenuFlyout>
|
</pilz:HeaderMenuItem>
|
||||||
</pilz:ImageButton.Flyout>
|
|
||||||
</pilz:ImageButton>
|
|
||||||
|
|
||||||
<!-- Button: Tools -->
|
<!-- MenuItem: Workspace -->
|
||||||
<pilz:ImageButton
|
<pilz:HeaderMenuItem
|
||||||
x:Name="ButtonTools"
|
x:Name="MenuItemTools"
|
||||||
Text="{x:Static langRes:GeneralLangRes.Tools}"
|
HeaderText="{x:Static langRes:GeneralLangRes.Tools}"/>
|
||||||
Background="Transparent"/>
|
</Menu.Items>
|
||||||
</StackPanel>
|
</Menu>
|
||||||
|
|
||||||
<!-- TreeView: Workspace -->
|
<!-- TreeView: Workspace -->
|
||||||
<ScrollViewer
|
<ScrollViewer
|
||||||
@@ -82,6 +71,7 @@
|
|||||||
|
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TreeView
|
<TreeView
|
||||||
|
x:Name="TreeViewWorkspace"
|
||||||
ItemsSource="{Binding CurrentTreeNodes}"
|
ItemsSource="{Binding CurrentTreeNodes}"
|
||||||
SelectedItem="{Binding SelectedTreeNode}">
|
SelectedItem="{Binding SelectedTreeNode}">
|
||||||
|
|
||||||
@@ -109,6 +99,20 @@
|
|||||||
Orientation="Horizontal"
|
Orientation="Horizontal"
|
||||||
VerticalAlignment="Center">
|
VerticalAlignment="Center">
|
||||||
|
|
||||||
|
<!-- Menu: Actions -->
|
||||||
|
<Menu>
|
||||||
|
<Menu.Items>
|
||||||
|
<pilz:HeaderMenuItem x:Name="MenuItemAddAction" HeaderText="{x:Static langRes:GeneralLangRes.Add}" Click="ButtonAddAction_OnClick"/>
|
||||||
|
<pilz:HeaderMenuItem x:Name="MenuItemRemoveAction" HeaderText="{x:Static langRes:GeneralLangRes.Remove}" Click="ButtonRemoveAction_OnClick"/>
|
||||||
|
</Menu.Items>
|
||||||
|
</Menu>
|
||||||
|
|
||||||
|
<!-- TextBox: Search -->
|
||||||
|
<TextBox
|
||||||
|
Width="200"
|
||||||
|
Watermark="{x:Static langRes:GeneralLangRes.Search}"
|
||||||
|
Text="{Binding CurrentGridRows.SearchText}"/>
|
||||||
|
|
||||||
<!-- Panel: Menu -->
|
<!-- Panel: Menu -->
|
||||||
<ContentControl
|
<ContentControl
|
||||||
Content="{Binding SelectedTreeNode}">
|
Content="{Binding SelectedTreeNode}">
|
||||||
@@ -118,33 +122,16 @@
|
|||||||
DataType="mainWindow:ActionSetTreeNode">
|
DataType="mainWindow:ActionSetTreeNode">
|
||||||
|
|
||||||
<StackPanel
|
<StackPanel
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal"
|
||||||
|
Spacing="6">
|
||||||
<!-- Button: Add action -->
|
|
||||||
<pilz:ImageButton
|
|
||||||
x:Name="ButtonAddAction"
|
|
||||||
Text="{x:Static langRes:GeneralLangRes.Add}"
|
|
||||||
ImageSource="{x:Static local:MainWindow.ButtonImageAddAction}"
|
|
||||||
Background="Transparent"
|
|
||||||
Click="ButtonAddAction_OnClick"/>
|
|
||||||
|
|
||||||
<!-- Button: Remove action -->
|
|
||||||
<pilz:ImageButton
|
|
||||||
x:Name="ButtonRemoveAction"
|
|
||||||
Text="{x:Static langRes:GeneralLangRes.Remove}"
|
|
||||||
ImageSource="{x:Static local:MainWindow.ButtonImageRemoveAction}"
|
|
||||||
Background="Transparent"
|
|
||||||
Click="ButtonRemoveAction_OnClick"/>
|
|
||||||
|
|
||||||
<!-- TextBox: Version -->
|
<!-- TextBox: Version -->
|
||||||
<TextBox
|
<TextBox
|
||||||
Margin="3, 0, 3, 0"
|
|
||||||
Width="100"
|
Width="100"
|
||||||
Text="{Binding Version}"/>
|
Text="{Binding Version}"/>
|
||||||
|
|
||||||
<!-- CheckBox: Is public -->
|
<!-- CheckBox: Is public -->
|
||||||
<CheckBox
|
<CheckBox
|
||||||
Margin="3, 0, 3, 0"
|
|
||||||
Content="{x:Static langRes:GeneralLangRes.Public}"
|
Content="{x:Static langRes:GeneralLangRes.Public}"
|
||||||
IsChecked="{Binding IsPublic}"/>
|
IsChecked="{Binding IsPublic}"/>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
@@ -172,7 +159,7 @@
|
|||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
x:Name="DataGridActions"
|
x:Name="DataGridActions"
|
||||||
VerticalAlignment="Stretch"
|
VerticalAlignment="Stretch"
|
||||||
ItemsSource="{Binding CurrentGridRows}"
|
ItemsSource="{Binding CurrentGridRows.View}"
|
||||||
SelectedItem="{Binding SelectedGridRow}">
|
SelectedItem="{Binding SelectedGridRow}">
|
||||||
|
|
||||||
<DataGrid.ContextMenu>
|
<DataGrid.ContextMenu>
|
||||||
@@ -182,24 +169,31 @@
|
|||||||
<DataGrid.Columns>
|
<DataGrid.Columns>
|
||||||
<DataGridTextColumn
|
<DataGridTextColumn
|
||||||
Header="{x:Static langRes:GeneralLangRes.Id}"
|
Header="{x:Static langRes:GeneralLangRes.Id}"
|
||||||
Binding="{Binding InheritedId}"/>
|
Binding="{Binding InheritedId}"
|
||||||
|
Width="*"/>
|
||||||
|
|
||||||
<DataGridTextColumn
|
<DataGridTextColumn
|
||||||
Header="{x:Static langRes:GeneralLangRes.Side}"
|
Header="{x:Static langRes:GeneralLangRes.Name}"
|
||||||
Binding="{Binding InheritedSide}"/>
|
Binding="{Binding InheritedName}"
|
||||||
|
Width="*"/>
|
||||||
|
|
||||||
<DataGridTextColumn
|
<DataGridTextColumn
|
||||||
Header="{x:Static langRes:GeneralLangRes.UpdateType}"
|
Header="{x:Static langRes:GeneralLangRes.UpdateType}"
|
||||||
Binding="{Binding InheritedUpdateType}"
|
Binding="{Binding InheritedUpdateType}"
|
||||||
IsVisible="{Binding IsUpdate}"/>
|
IsVisible="{Binding IsUpdate}"/>
|
||||||
|
|
||||||
|
<DataGridTextColumn
|
||||||
|
Header="{x:Static langRes:GeneralLangRes.Side}"
|
||||||
|
Binding="{Binding InheritedSide}"/>
|
||||||
|
|
||||||
<DataGridTextColumn
|
<DataGridTextColumn
|
||||||
Header="{x:Static langRes:GeneralLangRes.SourceType}"
|
Header="{x:Static langRes:GeneralLangRes.SourceType}"
|
||||||
Binding="{Binding InheritedSourceType}"/>
|
Binding="{Binding InheritedSourceType}"/>
|
||||||
|
|
||||||
<DataGridTextColumn
|
<DataGridTextColumn
|
||||||
Header="{x:Static langRes:GeneralLangRes.DestinationPath}"
|
Header="{x:Static langRes:GeneralLangRes.DestinationPath}"
|
||||||
Binding="{Binding InheritedDestPath}"/>
|
Binding="{Binding InheritedDestPath}"
|
||||||
|
Width="*"/>
|
||||||
|
|
||||||
<DataGridTemplateColumn
|
<DataGridTemplateColumn
|
||||||
Header="{x:Static langRes:GeneralLangRes.State}">
|
Header="{x:Static langRes:GeneralLangRes.State}">
|
||||||
@@ -356,7 +350,7 @@
|
|||||||
<!-- Source -->
|
<!-- Source -->
|
||||||
<Grid
|
<Grid
|
||||||
ColumnDefinitions="150,*"
|
ColumnDefinitions="150,*"
|
||||||
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto"
|
RowDefinitions="Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto,Auto"
|
||||||
RowSpacing="6"
|
RowSpacing="6"
|
||||||
ColumnSpacing="6">
|
ColumnSpacing="6">
|
||||||
|
|
||||||
@@ -402,23 +396,30 @@
|
|||||||
x:Name="TextBoxInstallActionSourceName"
|
x:Name="TextBoxInstallActionSourceName"
|
||||||
Text="{Binding SourceName}"/>
|
Text="{Binding SourceName}"/>
|
||||||
|
|
||||||
<!-- Source RegEx -->
|
<!-- Source tag -->
|
||||||
<Label Grid.Row="5" Grid.Column="0" Content="{x:Static langRes:GeneralLangRes.SourceRegex}" Target="TextBoxInstallActionSourceRegEx"/>
|
<Label Grid.Row="5" Grid.Column="0" Content="{x:Static langRes:GeneralLangRes.SourceTag}" Target="TextBoxInstallActionSourceTag"/>
|
||||||
<TextBox
|
<TextBox
|
||||||
Grid.Row="5" Grid.Column="1"
|
Grid.Row="5" Grid.Column="1"
|
||||||
|
x:Name="TextBoxInstallActionSourceTag"
|
||||||
|
Text="{Binding SourceTag}"/>
|
||||||
|
|
||||||
|
<!-- Source RegEx -->
|
||||||
|
<Label Grid.Row="6" Grid.Column="0" Content="{x:Static langRes:GeneralLangRes.SourceRegex}" Target="TextBoxInstallActionSourceRegEx"/>
|
||||||
|
<TextBox
|
||||||
|
Grid.Row="6" Grid.Column="1"
|
||||||
x:Name="TextBoxInstallActionSourceRegEx"
|
x:Name="TextBoxInstallActionSourceRegEx"
|
||||||
Text="{Binding SourceRegex}"/>
|
Text="{Binding SourceRegex}"/>
|
||||||
|
|
||||||
<!-- Source url -->
|
<!-- Source url -->
|
||||||
<Label Grid.Row="6" Grid.Column="0" Content="{x:Static langRes:GeneralLangRes.SourceUrl}" Target="TextBoxInstallActionSourceUrl"/>
|
<Label Grid.Row="7" Grid.Column="0" Content="{x:Static langRes:GeneralLangRes.SourceUrl}" Target="TextBoxInstallActionSourceUrl"/>
|
||||||
<TextBox
|
<TextBox
|
||||||
Grid.Row="6" Grid.Column="1"
|
Grid.Row="7" Grid.Column="1"
|
||||||
x:Name="TextBoxInstallActionSourceUrl" Text="{Binding SourceUrl}"/>
|
x:Name="TextBoxInstallActionSourceUrl" Text="{Binding SourceUrl}"/>
|
||||||
|
|
||||||
<!-- Zip archive path -->
|
<!-- Zip archive path -->
|
||||||
<Label Grid.Row="7" Grid.Column="0" Content="{x:Static langRes:GeneralLangRes.ZipArchivePath}" Target="TextBoxInstallActionZipArchivePath"/>
|
<Label Grid.Row="8" Grid.Column="0" Content="{x:Static langRes:GeneralLangRes.ZipArchivePath}" Target="TextBoxInstallActionZipArchivePath"/>
|
||||||
<TextBox
|
<TextBox
|
||||||
Grid.Row="7" Grid.Column="1"
|
Grid.Row="8" Grid.Column="1"
|
||||||
x:Name="TextBoxInstallActionZipArchivePath"
|
x:Name="TextBoxInstallActionZipArchivePath"
|
||||||
Text="{Binding ZipPath}"/>
|
Text="{Binding ZipPath}"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ using System.Reflection;
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Media;
|
using DynamicData;
|
||||||
using ModpackUpdater.Apps.Manager.Api;
|
using ModpackUpdater.Apps.Manager.Api;
|
||||||
using ModpackUpdater.Apps.Manager.Api.Model;
|
using ModpackUpdater.Apps.Manager.Api.Model;
|
||||||
using ModpackUpdater.Apps.Manager.Api.Plugins.Features;
|
using ModpackUpdater.Apps.Manager.Api.Plugins.Features;
|
||||||
@@ -10,6 +10,7 @@ using ModpackUpdater.Apps.Manager.Api.Plugins.Params;
|
|||||||
using ModpackUpdater.Apps.Manager.Settings;
|
using ModpackUpdater.Apps.Manager.Settings;
|
||||||
using ModpackUpdater.Apps.Manager.Ui.Models.MainWindow;
|
using ModpackUpdater.Apps.Manager.Ui.Models.MainWindow;
|
||||||
using Pilz.Extensions;
|
using Pilz.Extensions;
|
||||||
|
using Pilz.Extensions.Collections;
|
||||||
using Pilz.Features;
|
using Pilz.Features;
|
||||||
using Pilz.UI.AvaloniaUI.Features;
|
using Pilz.UI.AvaloniaUI.Features;
|
||||||
using Pilz.UI.Symbols;
|
using Pilz.UI.Symbols;
|
||||||
@@ -18,9 +19,6 @@ namespace ModpackUpdater.Apps.Manager.Ui;
|
|||||||
|
|
||||||
public partial class MainWindow : Window, IMainApi
|
public partial class MainWindow : Window, IMainApi
|
||||||
{
|
{
|
||||||
public static IImage? ButtonImageAddAction => AppGlobals.Symbols.GetImageSource(AppSymbols.add);
|
|
||||||
public static IImage? ButtonImageRemoveAction => AppGlobals.Symbols.GetImageSource(AppSymbols.remove);
|
|
||||||
|
|
||||||
private WorkspaceFeature? curWs;
|
private WorkspaceFeature? curWs;
|
||||||
|
|
||||||
public MainWindowViewModel Model { get; } = new();
|
public MainWindowViewModel Model { get; } = new();
|
||||||
@@ -32,19 +30,21 @@ public partial class MainWindow : Window, IMainApi
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
Title = $"{Title} (v{Assembly.GetExecutingAssembly().GetAppVersion().ToShortString()})";
|
Title = $"{Title} (v{Assembly.GetExecutingAssembly().GetAppVersion().ToShortHumanString()})";
|
||||||
|
|
||||||
GridMain.DataContext = Model;
|
GridMain.DataContext = Model;
|
||||||
|
|
||||||
ButtonWorkspace.ImageSource = AppGlobals.Symbols.GetImageSource(AppSymbols.workspace);
|
MenuItemWorkspace.Icon = AppGlobals.Symbols.GetImage(AppSymbols.workspace, SymbolSize.Small);
|
||||||
MenuItemWorkspacePreferences.Icon = AppGlobals.Symbols.GetImage(AppSymbols.settings, SymbolSize.Small);
|
MenuItemWorkspacePreferences.Icon = AppGlobals.Symbols.GetImage(AppSymbols.settings, SymbolSize.Small);
|
||||||
MenuItemSaveWorkspace.Icon = AppGlobals.Symbols.GetImage(AppSymbols.save, SymbolSize.Small);
|
MenuItemSaveWorkspace.Icon = AppGlobals.Symbols.GetImage(AppSymbols.save, SymbolSize.Small);
|
||||||
MenuItemNewWorkspace.Icon = AppGlobals.Symbols.GetImage(AppSymbols.new_window, SymbolSize.Small);
|
MenuItemNewWorkspace.Icon = AppGlobals.Symbols.GetImage(AppSymbols.new_window, SymbolSize.Small);
|
||||||
MenuItemRecentWorkspaces.Icon = AppGlobals.Symbols.GetImage(AppSymbols.time_machine, SymbolSize.Small);
|
MenuItemRecentWorkspaces.Icon = AppGlobals.Symbols.GetImage(AppSymbols.time_machine, SymbolSize.Small);
|
||||||
ButtonUpdate.ImageSource = AppGlobals.Symbols.GetImageSource(AppSymbols.update_done);
|
MenuItemUpdate.Icon = AppGlobals.Symbols.GetImage(AppSymbols.update_done, SymbolSize.Small);
|
||||||
ButtonTools.ImageSource = AppGlobals.Symbols.GetImageSource(AppSymbols.tools);
|
MenuItemTools.Icon = AppGlobals.Symbols.GetImage(AppSymbols.tools, SymbolSize.Small);
|
||||||
MenuItemCreateUpdate.Icon = AppGlobals.Symbols.GetImage(AppSymbols.add, SymbolSize.Small);
|
MenuItemCreateUpdate.Icon = AppGlobals.Symbols.GetImage(AppSymbols.add, SymbolSize.Small);
|
||||||
MenuItemRemoveUpdate.Icon = AppGlobals.Symbols.GetImage(AppSymbols.remove, SymbolSize.Small);
|
MenuItemRemoveUpdate.Icon = AppGlobals.Symbols.GetImage(AppSymbols.remove, SymbolSize.Small);
|
||||||
|
MenuItemAddAction.HeaderIcon = AppGlobals.Symbols.GetImage(AppSymbols.add, SymbolSize.Small);
|
||||||
|
MenuItemRemoveAction.HeaderIcon = AppGlobals.Symbols.GetImage(AppSymbols.remove, SymbolSize.Small);
|
||||||
ImageUpdate.Source = AppGlobals.Symbols.GetImageSource(AppSymbols.update_done);
|
ImageUpdate.Source = AppGlobals.Symbols.GetImageSource(AppSymbols.update_done);
|
||||||
ImageMetadata.Source = AppGlobals.Symbols.GetImageSource(AppSymbols.show_property);
|
ImageMetadata.Source = AppGlobals.Symbols.GetImageSource(AppSymbols.show_property);
|
||||||
ImageGeneral.Source = AppGlobals.Symbols.GetImageSource(AppSymbols.normal_screen);
|
ImageGeneral.Source = AppGlobals.Symbols.GetImageSource(AppSymbols.normal_screen);
|
||||||
@@ -59,9 +59,7 @@ public partial class MainWindow : Window, IMainApi
|
|||||||
customClickHandler: MenuItemActionItem_Click,
|
customClickHandler: MenuItemActionItem_Click,
|
||||||
insertPrioSplitters: true);
|
insertPrioSplitters: true);
|
||||||
|
|
||||||
var menuFlyoutTools = new MenuFlyout();
|
PluginFeatureController.Instance.Functions.Get(FeatureTypes.Tools).InsertItemsTo(MenuItemTools.Items,
|
||||||
ButtonTools.Flyout = menuFlyoutTools;
|
|
||||||
PluginFeatureController.Instance.Functions.Get(FeatureTypes.Tools).InsertItemsTo(menuFlyoutTools.Items,
|
|
||||||
customClickHandler: MenuItemToolsItem_Click,
|
customClickHandler: MenuItemToolsItem_Click,
|
||||||
insertPrioSplitters: true);
|
insertPrioSplitters: true);
|
||||||
}
|
}
|
||||||
@@ -118,18 +116,18 @@ public partial class MainWindow : Window, IMainApi
|
|||||||
private static void AddToRecentFiles(IWorkspace workspace)
|
private static void AddToRecentFiles(IWorkspace workspace)
|
||||||
{
|
{
|
||||||
var settings = Program.Settings.Get<WorkspaceSettings>();
|
var settings = Program.Settings.Get<WorkspaceSettings>();
|
||||||
|
settings.Workspaces.RemoveAll(n => n == workspace.Config);
|
||||||
settings.Workspaces.Remove(workspace.Config);
|
|
||||||
settings.Workspaces.Insert(0, workspace.Config);
|
settings.Workspaces.Insert(0, workspace.Config);
|
||||||
|
settings.Workspaces.Skip(20).ForEach(n => settings.Workspaces.Remove(n));
|
||||||
while (settings.Workspaces.Count > 20)
|
|
||||||
settings.Workspaces.RemoveAt(20);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Window_OnLoaded(object? sender, RoutedEventArgs e)
|
private async void Window_OnLoaded(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
var updater = new AppUpdates(Program.UpdateUrl, this);
|
var updater = new AppUpdates("manager", this)
|
||||||
updater.OnDownloadProgramUpdate += (o, args) => Model.Progress.Start();
|
{
|
||||||
|
UsePopups = true,
|
||||||
|
};
|
||||||
|
updater.OnDownloadProgramUpdate += (_, _) => Model.Progress.Start();
|
||||||
await updater.UpdateApp();
|
await updater.UpdateApp();
|
||||||
Model.Progress.Stop();
|
Model.Progress.Stop();
|
||||||
|
|
||||||
@@ -203,7 +201,10 @@ public partial class MainWindow : Window, IMainApi
|
|||||||
Version = new(),
|
Version = new(),
|
||||||
};
|
};
|
||||||
Model.CurrentWorkspace.UpdateInfos.Updates.Insert(0, update);
|
Model.CurrentWorkspace.UpdateInfos.Updates.Insert(0, update);
|
||||||
nodeUpdates.Nodes.Insert(0, new ActionSetTreeNode(update));
|
var item = new ActionSetTreeNode(update);
|
||||||
|
nodeUpdates.Nodes.Insert(0, item);
|
||||||
|
TreeViewWorkspace.SelectedItem = item;
|
||||||
|
TreeViewWorkspace.ScrollIntoView(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void MenuItemRemoveUpdate_OnClick(object? sender, RoutedEventArgs e)
|
private void MenuItemRemoveUpdate_OnClick(object? sender, RoutedEventArgs e)
|
||||||
@@ -239,7 +240,10 @@ public partial class MainWindow : Window, IMainApi
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rows.Add(new MainWindowGridRow(action, rootInfos));
|
var row = new MainWindowGridRow(action, rootInfos);
|
||||||
|
rows.List.Add(row);
|
||||||
|
DataGridActions.SelectedItem = row;
|
||||||
|
DataGridActions.ScrollIntoView(row, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ButtonRemoveAction_OnClick(object? sender, RoutedEventArgs e)
|
private void ButtonRemoveAction_OnClick(object? sender, RoutedEventArgs e)
|
||||||
@@ -262,6 +266,6 @@ public partial class MainWindow : Window, IMainApi
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
rows.Remove(row);
|
rows.List.Remove(row);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
34
ModpackUpdater.Apps.Manager/Ui/Models/DynamicDataView.cs
Normal file
34
ModpackUpdater.Apps.Manager/Ui/Models/DynamicDataView.cs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
using System.Reactive.Subjects;
|
||||||
|
using DynamicData;
|
||||||
|
|
||||||
|
namespace ModpackUpdater.Apps.Manager.Ui.Models;
|
||||||
|
|
||||||
|
public class DynamicDataView<T> : INotifyPropertyChanged where T : notnull
|
||||||
|
{
|
||||||
|
public event PropertyChangedEventHandler? PropertyChanged;
|
||||||
|
|
||||||
|
private string? searchText;
|
||||||
|
private readonly Subject<string?> searchTextSubject = new();
|
||||||
|
|
||||||
|
public SourceList<T> List { get; } = new();
|
||||||
|
public ReadOnlyObservableCollection<T> View { get; }
|
||||||
|
|
||||||
|
public DynamicDataView(Func<string?, Func<T, bool>> predicate)
|
||||||
|
{
|
||||||
|
List.Connect()
|
||||||
|
.Filter(searchTextSubject/*.Throttle(TimeSpan.FromMilliseconds(250))*/.Select(predicate))
|
||||||
|
.Bind(out var view)
|
||||||
|
.Subscribe();
|
||||||
|
searchTextSubject?.OnNext(searchText);
|
||||||
|
View = view;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string? SearchText
|
||||||
|
{
|
||||||
|
get => searchText;
|
||||||
|
set => searchTextSubject.OnNext(searchText = value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -23,15 +23,22 @@ public class MainWindowGridRow(InstallAction action, IActionSet baseActions) : I
|
|||||||
|
|
||||||
[DependsOn(nameof(Id), nameof(InheritFrom))]
|
[DependsOn(nameof(Id), nameof(InheritFrom))]
|
||||||
public string? InheritedId => action is UpdateAction ua && !string.IsNullOrWhiteSpace(ua.InheritFrom) ? ua.InheritFrom : action.Id;
|
public string? InheritedId => action is UpdateAction ua && !string.IsNullOrWhiteSpace(ua.InheritFrom) ? ua.InheritFrom : action.Id;
|
||||||
|
|
||||||
[DependsOn(nameof(Side), nameof(InheritedId), nameof(Id))]
|
[DependsOn(nameof(Side), nameof(InheritedId), nameof(Id))]
|
||||||
public string InheritedSide => Sides[Inherited.Side];
|
public string InheritedSide => Sides[Inherited.Side];
|
||||||
|
|
||||||
[DependsOn(nameof(UpdateType), nameof(InheritedId), nameof(Id))]
|
[DependsOn(nameof(UpdateType), nameof(InheritedId), nameof(Id))]
|
||||||
public string InheritedUpdateType => action is UpdateAction ua ? UpdateActionTypes[ua.Type] : string.Empty;
|
public string InheritedUpdateType => action is UpdateAction ua ? UpdateActionTypes[ua.Type] : string.Empty;
|
||||||
|
|
||||||
[DependsOn(nameof(SourceType), nameof(InheritedId), nameof(Id))]
|
[DependsOn(nameof(SourceType), nameof(InheritedId), nameof(Id))]
|
||||||
public string InheritedSourceType => SourceTypes[Inherited.SourceType];
|
public string InheritedSourceType => SourceTypes[Inherited.SourceType];
|
||||||
|
|
||||||
[DependsOn(nameof(DestPath), nameof(InheritedId), nameof(Id))]
|
[DependsOn(nameof(DestPath), nameof(InheritedId), nameof(Id))]
|
||||||
public string? InheritedDestPath => Inherited.DestPath;
|
public string? InheritedDestPath => Inherited.DestPath;
|
||||||
|
|
||||||
|
[DependsOn(nameof(Name), nameof(InheritedId), nameof(Id))]
|
||||||
|
public string? InheritedName => Inherited.Name;
|
||||||
|
|
||||||
public string? Id
|
public string? Id
|
||||||
{
|
{
|
||||||
get => action.Id;
|
get => action.Id;
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ public class MainWindowViewModel : INotifyPropertyChanged
|
|||||||
public event PropertyChangedEventHandler? PropertyChanged;
|
public event PropertyChangedEventHandler? PropertyChanged;
|
||||||
|
|
||||||
private ObservableCollection<MainWindowTreeNode>? currentTreeNodes;
|
private ObservableCollection<MainWindowTreeNode>? currentTreeNodes;
|
||||||
private ObservableCollection<MainWindowGridRow>? currentGridRows;
|
|
||||||
private MainWindowTreeNode? selectedTreeNode;
|
private MainWindowTreeNode? selectedTreeNode;
|
||||||
private IWorkspace? currentWorkspace;
|
private IWorkspace? currentWorkspace;
|
||||||
|
|
||||||
public bool IsUpdate => selectedTreeNode is ActionSetTreeNode node && node.Infos is UpdateInfo;
|
public bool IsUpdate => selectedTreeNode is ActionSetTreeNode node && node.Infos is UpdateInfo;
|
||||||
public ProgressInfos Progress { get; } = new();
|
public ProgressInfos Progress { get; } = new();
|
||||||
public MainWindowGridRow? SelectedGridRow { get; set; }
|
public MainWindowGridRow? SelectedGridRow { get; set; }
|
||||||
|
public DynamicDataView<MainWindowGridRow> CurrentGridRows { get; } = new(FilterGridRows);
|
||||||
|
|
||||||
[AlsoNotifyFor(nameof(CurrentTreeNodes))]
|
[AlsoNotifyFor(nameof(CurrentTreeNodes))]
|
||||||
public IWorkspace? CurrentWorkspace
|
public IWorkspace? CurrentWorkspace
|
||||||
@@ -48,24 +48,38 @@ public class MainWindowViewModel : INotifyPropertyChanged
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[AlsoNotifyFor(nameof(CurrentGridRows))]
|
|
||||||
public MainWindowTreeNode? SelectedTreeNode
|
public MainWindowTreeNode? SelectedTreeNode
|
||||||
{
|
{
|
||||||
get => selectedTreeNode;
|
get => selectedTreeNode;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
currentGridRows = null;
|
|
||||||
selectedTreeNode = value;
|
selectedTreeNode = value;
|
||||||
|
CurrentGridRows.List.Edit(list =>
|
||||||
|
{
|
||||||
|
list.Clear();
|
||||||
|
if (CurrentWorkspace?.InstallInfos != null && selectedTreeNode is ActionSetTreeNode node)
|
||||||
|
list.AddRange(node.Infos.Actions.Select(n => new MainWindowGridRow(n, CurrentWorkspace.InstallInfos)));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObservableCollection<MainWindowGridRow>? CurrentGridRows
|
private static Func<MainWindowGridRow, bool> FilterGridRows(string? searchText)
|
||||||
{
|
{
|
||||||
get
|
return n => string.IsNullOrWhiteSpace(searchText)
|
||||||
{
|
|| (!string.IsNullOrWhiteSpace(n.Name) && n.Name.Contains(searchText))
|
||||||
if (currentGridRows == null && CurrentWorkspace?.InstallInfos != null && selectedTreeNode is ActionSetTreeNode node)
|
|| (!string.IsNullOrWhiteSpace(n.InheritFrom) && n.InheritFrom.Contains(searchText))
|
||||||
currentGridRows = [.. node.Infos.Actions.Select(n => new MainWindowGridRow(n, CurrentWorkspace.InstallInfos))];
|
|| (!string.IsNullOrWhiteSpace(n.InheritedDestPath) && n.InheritedDestPath.Contains(searchText))
|
||||||
return currentGridRows;
|
|| (!string.IsNullOrWhiteSpace(n.InheritedId) && n.InheritedId.Contains(searchText))
|
||||||
}
|
|| (!string.IsNullOrWhiteSpace(n.InheritedSide) && n.InheritedSide.Contains(searchText))
|
||||||
|
|| (!string.IsNullOrWhiteSpace(n.InheritedSourceType) && n.InheritedSourceType.Contains(searchText))
|
||||||
|
|| (!string.IsNullOrWhiteSpace(n.InheritedUpdateType) && n.InheritedUpdateType.Contains(searchText))
|
||||||
|
|| (!string.IsNullOrWhiteSpace(n.SourceName) && n.SourceName.Contains(searchText))
|
||||||
|
|| (!string.IsNullOrWhiteSpace(n.SourceOwner) && n.SourceOwner.Contains(searchText))
|
||||||
|
|| (!string.IsNullOrWhiteSpace(n.SourceRegex) && n.SourceRegex.Contains(searchText))
|
||||||
|
|| (!string.IsNullOrWhiteSpace(n.SourceTag) && n.SourceTag.Contains(searchText))
|
||||||
|
|| (!string.IsNullOrWhiteSpace(n.SourceUrl) && n.SourceUrl.Contains(searchText))
|
||||||
|
|| (!string.IsNullOrWhiteSpace(n.SrcPath) && n.SrcPath.Contains(searchText))
|
||||||
|
|| (!string.IsNullOrWhiteSpace(n.Website) && n.Website.Contains(searchText))
|
||||||
|
;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,9 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
|
using System.Reactive;
|
||||||
|
using System.Reactive.Linq;
|
||||||
|
using System.Reactive.Subjects;
|
||||||
|
using DynamicData;
|
||||||
using PropertyChanged;
|
using PropertyChanged;
|
||||||
|
|
||||||
namespace ModpackUpdater.Apps.Manager.Ui.Models.UpdatesCollectorViewMode;
|
namespace ModpackUpdater.Apps.Manager.Ui.Models.UpdatesCollectorViewMode;
|
||||||
@@ -9,6 +13,10 @@ public class UpdatesCollectorViewModel : INotifyPropertyChanged
|
|||||||
public event PropertyChangedEventHandler? PropertyChanged;
|
public event PropertyChangedEventHandler? PropertyChanged;
|
||||||
|
|
||||||
public ProgressInfos Progress { get; } = new();
|
public ProgressInfos Progress { get; } = new();
|
||||||
public string? SearchText { get; set; }
|
public DynamicDataView<ModUpdateInfo> Updates { get; } = new(FilterUpdates);
|
||||||
public ObservableCollection<ModUpdateInfo> Updates { get; } = [];
|
|
||||||
|
private static Func<ModUpdateInfo, bool> FilterUpdates(string? searchText)
|
||||||
|
{
|
||||||
|
return n => string.IsNullOrWhiteSpace(searchText) || (n.Origin.Name != null && n.Origin.Name.Contains(searchText, StringComparison.InvariantCultureIgnoreCase));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -25,16 +25,15 @@
|
|||||||
<!-- TextBox: Search -->
|
<!-- TextBox: Search -->
|
||||||
<TextBox
|
<TextBox
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Watermark="Search"
|
Watermark="{x:Static langRes:GeneralLangRes.Search}"
|
||||||
Text="{Binding SearchText}"
|
Text="{Binding Updates.SearchText}"/>
|
||||||
TextChanged="TextBoxSearch_OnTextChanged"/>
|
|
||||||
|
|
||||||
<!-- ScrollViewer: Updates -->
|
<!-- ScrollViewer: Updates -->
|
||||||
<ScrollViewer
|
<ScrollViewer
|
||||||
Grid.Row="1">
|
Grid.Row="1">
|
||||||
|
|
||||||
<ItemsControl
|
<ItemsControl
|
||||||
ItemsSource="{Binding Updates}">
|
ItemsSource="{Binding Updates.View}">
|
||||||
|
|
||||||
<ItemsControl.ItemTemplate>
|
<ItemsControl.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
@@ -43,8 +42,7 @@
|
|||||||
ColumnDefinitions="20*,20*,20*,Auto"
|
ColumnDefinitions="20*,20*,20*,Auto"
|
||||||
ColumnSpacing="6"
|
ColumnSpacing="6"
|
||||||
RowSpacing="6"
|
RowSpacing="6"
|
||||||
Margin="3"
|
Margin="3">
|
||||||
IsVisible="{Binding Visible}">
|
|
||||||
|
|
||||||
<!-- Label: Name -->
|
<!-- Label: Name -->
|
||||||
<TextBlock
|
<TextBlock
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
|
using DynamicData;
|
||||||
using ModpackUpdater.Apps.Manager.Api.Model;
|
using ModpackUpdater.Apps.Manager.Api.Model;
|
||||||
using ModpackUpdater.Apps.Manager.Ui.Models.UpdatesCollectorViewMode;
|
using ModpackUpdater.Apps.Manager.Ui.Models.UpdatesCollectorViewMode;
|
||||||
using ModpackUpdater.Manager;
|
using ModpackUpdater.Manager;
|
||||||
@@ -36,7 +37,7 @@ public partial class UpdatesCollectorView : AvaloniaFlyoutBase
|
|||||||
if (updates == null || updates.Length == 0 || updates[0].Tag == action.SourceTag)
|
if (updates == null || updates.Length == 0 || updates[0].Tag == action.SourceTag)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Model.Updates.Add(new(updates, action));
|
Model.Updates.List.Add(new(updates, action));
|
||||||
|
|
||||||
if (IsClosed)
|
if (IsClosed)
|
||||||
break;
|
break;
|
||||||
@@ -47,7 +48,7 @@ public partial class UpdatesCollectorView : AvaloniaFlyoutBase
|
|||||||
|
|
||||||
protected override object GetResult()
|
protected override object GetResult()
|
||||||
{
|
{
|
||||||
return new ModUpdates(Model.Updates);
|
return new ModUpdates([.. Model.Updates.List.Items]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async void Me_OnLoaded(object? sender, RoutedEventArgs e)
|
private async void Me_OnLoaded(object? sender, RoutedEventArgs e)
|
||||||
@@ -55,18 +56,9 @@ public partial class UpdatesCollectorView : AvaloniaFlyoutBase
|
|||||||
await FindUpdates();
|
await FindUpdates();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TextBoxSearch_OnTextChanged(object? sender, TextChangedEventArgs e)
|
|
||||||
{
|
|
||||||
var searchString = Model.SearchText?.Trim().ToLowerInvariant();
|
|
||||||
var hasNoSearch = string.IsNullOrWhiteSpace(searchString);
|
|
||||||
|
|
||||||
foreach (var item in Model.Updates)
|
|
||||||
item.Visible = hasNoSearch || (item.Origin.Name != null && item.Origin.Name.Contains(searchString!, StringComparison.InvariantCultureIgnoreCase));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ButtonRemoveUpdate_Click(object? sender, RoutedEventArgs e)
|
private void ButtonRemoveUpdate_Click(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (sender is Button button && button.DataContext is ModUpdateInfo update)
|
if (sender is Button button && button.DataContext is ModUpdateInfo update)
|
||||||
Model.Updates.Remove(update);
|
Model.Updates.List.Remove(update);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
pupnet -y -v "$1[1]" -r linux-x64 -k appimage
|
|
||||||
#pupnet -y -v "$1[1]" -r linux-x64 -k flatpak -p DefineConstants=DISABLE_UPDATE
|
|
||||||
#pupnet -y -v "$1[1]"-r linux-x64 -k deb -p DefineConstants=DISABLE_UPDATE
|
|
||||||
#pupnet -y -v "$1[1]"-r linux-x64 -k rpm -p DefineConstants=DISABLE_UPDATE
|
|
||||||
pupnet -y -v "$1[1]" -r linux-arm64 -k appimage
|
|
||||||
#pupnet -y -v "$1[1]" -r linux-arm64 -k flatpak -p DefineConstants=DISABLE_UPDATE
|
|
||||||
#pupnet -y -v "$1[1]"-r linux-arm64 -k deb -p DefineConstants=DISABLE_UPDATE
|
|
||||||
#pupnet -y -v "$1[1]"-r linux-arm64 -k rpm -p DefineConstants=DISABLE_UPDATE
|
|
||||||
pupnet -y -v "$1[1]" -r win-x64 -k zip
|
|
||||||
pupnet -y -v "$1[1]" -r win-arm64 -k zip
|
|
||||||
pupnet -y -v "$1[1]" -r osx-x64 -k zip
|
|
||||||
pupnet -y -v "$1[1]" -r osx-arm64 -k zip
|
|
||||||
@@ -10,13 +10,19 @@ using Pilz.Updating.Client;
|
|||||||
|
|
||||||
namespace ModpackUpdater.Apps;
|
namespace ModpackUpdater.Apps;
|
||||||
|
|
||||||
public class AppUpdates(string updateUrl, Window mainWindow)
|
public class AppUpdates(string appShortName, Window mainWindow)
|
||||||
{
|
{
|
||||||
|
public const string UpdateUrl = "https://git.pilzinsel64.de/LITW-Refined/minecraft-modpack-updater/raw/branch/updates/updates.json";
|
||||||
|
|
||||||
public event EventHandler? OnDownloadProgramUpdate;
|
public event EventHandler? OnDownloadProgramUpdate;
|
||||||
|
|
||||||
|
public bool UsePopups { get; set; }
|
||||||
|
|
||||||
public async Task UpdateApp()
|
public async Task UpdateApp()
|
||||||
{
|
{
|
||||||
#if !DISABLE_UPDATE
|
#if DISABLE_UPDATE
|
||||||
|
await Task.CompletedTask;
|
||||||
|
#else
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await UpdateAppCore();
|
await UpdateAppCore();
|
||||||
@@ -35,25 +41,33 @@ public class AppUpdates(string updateUrl, Window mainWindow)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var myAppPath = EnvironmentEx.ProcessPath!;
|
var myAppPath = EnvironmentEx.ProcessPath!;
|
||||||
var updater = new UpdateClient(updateUrl, Assembly.GetEntryAssembly()!.GetAppVersion(), AppChannel.Stable)
|
var updater = new UpdateClient(UpdateUrl, Assembly.GetEntryAssembly()!.GetAppVersion(), AppChannel.Stable)
|
||||||
{
|
{
|
||||||
Distro = RuntimeInformationsEx.GetRuntimeIdentifier(),
|
Distro = $"{appShortName}-{RuntimeInformationsEx.GetRuntimeIdentifier()}",
|
||||||
};
|
};
|
||||||
|
|
||||||
if (await updater.CheckForUpdate() is {} packageToInstall
|
if (await updater.CheckForUpdate() is not { } packageToInstall || await AskForUpdate() != ButtonResult.Yes)
|
||||||
&& await MessageBoxManager.GetMessageBoxStandard(GeneralMsgBoxLangRes.UpdateAvailable_Title, GeneralMsgBoxLangRes.UpdateAvailable, ButtonEnum.YesNo, MsBox.Avalonia.Enums.Icon.Info).ShowWindowDialogAsync(mainWindow) == ButtonResult.Yes)
|
return;
|
||||||
{
|
|
||||||
OnDownloadProgramUpdate?.Invoke(this, EventArgs.Empty);
|
OnDownloadProgramUpdate?.Invoke(this, EventArgs.Empty);
|
||||||
mainWindow.IsEnabled = false;
|
mainWindow.IsEnabled = false;
|
||||||
if (await updater.DownloadPackageAsync(packageToInstall)
|
|
||||||
&& await updater.InstallPackageAsync(packageToInstall, myAppPath))
|
if (await updater.DownloadPackageAsync(packageToInstall) && await updater.InstallPackageAsync(packageToInstall, myAppPath))
|
||||||
{
|
{
|
||||||
mainWindow.IsVisible = false;
|
mainWindow.IsVisible = false;
|
||||||
await Process.Start(myAppPath).WaitForExitAsync();
|
await Process.Start(myAppPath).WaitForExitAsync();
|
||||||
Environment.Exit(0);
|
Environment.Exit(0);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mainWindow.IsEnabled = true;
|
mainWindow.IsEnabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Task<ButtonResult> AskForUpdate()
|
||||||
|
{
|
||||||
|
var msgBox = MessageBoxManager.GetMessageBoxStandard(GeneralMsgBoxLangRes.UpdateAvailable_Title, GeneralMsgBoxLangRes.UpdateAvailable, ButtonEnum.YesNo, Icon.Info);
|
||||||
|
if (UsePopups)
|
||||||
|
return msgBox.ShowAsPopupAsync(mainWindow);
|
||||||
|
return msgBox.ShowWindowDialogAsync(mainWindow);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -19,22 +19,22 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Pilz" Version="2.6.1" />
|
<PackageReference Include="Pilz" Version="2.7.8" />
|
||||||
<PackageReference Include="Pilz.UI" Version="3.1.4" />
|
<PackageReference Include="Pilz.UI" Version="3.1.5" />
|
||||||
<PackageReference Include="Pilz.UI.AvaloniaUI" Version="1.2.18" />
|
<PackageReference Include="Pilz.UI.AvaloniaUI" Version="1.2.21" />
|
||||||
<PackageReference Include="MessageBox.Avalonia" Version="3.3.0" />
|
<PackageReference Include="MessageBox.Avalonia" Version="3.3.1" />
|
||||||
<PackageReference Include="Avalonia" Version="11.3.8" />
|
<PackageReference Include="Avalonia" Version="11.3.10" />
|
||||||
<PackageReference Include="Avalonia.Desktop" Version="11.3.8" />
|
<PackageReference Include="Avalonia.Desktop" Version="11.3.10" />
|
||||||
<PackageReference Include="Avalonia.Svg" Version="11.3.0" />
|
<PackageReference Include="Avalonia.Svg" Version="11.3.0" />
|
||||||
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.3.8" />
|
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.3.10" />
|
||||||
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.3.8" />
|
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.3.10" />
|
||||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
||||||
<PackageReference Include="Avalonia.Diagnostics" Version="11.3.8">
|
<PackageReference Include="Avalonia.Diagnostics" Version="11.3.10">
|
||||||
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
|
<IncludeAssets Condition="'$(Configuration)' != 'Debug'">None</IncludeAssets>
|
||||||
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
<PrivateAssets Condition="'$(Configuration)' != 'Debug'">All</PrivateAssets>
|
||||||
</PackageReference>
|
</PackageReference>
|
||||||
<PackageReference Include="Pilz.Updating" Version="4.3.5" />
|
<PackageReference Include="Pilz.Updating" Version="4.3.6" />
|
||||||
<PackageReference Include="Pilz.Updating.Client" Version="4.4.6" />
|
<PackageReference Include="Pilz.Updating.Client" Version="4.4.8" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -12,7 +12,10 @@ public class ModpackFactory
|
|||||||
{
|
{
|
||||||
Credentials = new Credentials("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"),
|
Credentials = new Credentials("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"),
|
||||||
};
|
};
|
||||||
private readonly ApiClient curseForge = new("$2a$10$pE4dD09gmr7IcOe8hjWhleWWjXopJcDNpq1P9FlrDMCBw05pCyAXa", "pilzinsel64@gmx.de");
|
private readonly ApiClient curseForge = new("$2a$10$pE4dD09gmr7IcOe8hjWhleWWjXopJcDNpq1P9FlrDMCBw05pCyAXa", "pilzinsel64@gmx.de")
|
||||||
|
{
|
||||||
|
RequestTimeout = new TimeSpan(0, 0, 30),
|
||||||
|
};
|
||||||
private readonly ModrinthClient modrinth = new(new ModrinthClientConfig
|
private readonly ModrinthClient modrinth = new(new ModrinthClientConfig
|
||||||
{
|
{
|
||||||
ModrinthToken = "mrp_zUlDSET5actMUdTU3FK242TXgvlWgaErSSEFuegNG7thLgkC50IiK2NCGOzW",
|
ModrinthToken = "mrp_zUlDSET5actMUdTU3FK242TXgvlWgaErSSEFuegNG7thLgkC50IiK2NCGOzW",
|
||||||
@@ -70,7 +73,7 @@ public class ModpackFactory
|
|||||||
{
|
{
|
||||||
var repo = await github.Repository.Get(action.SourceOwner, action.SourceName);
|
var repo = await github.Repository.Get(action.SourceOwner, action.SourceName);
|
||||||
var releases = await github.Repository.Release.GetAll(repo.Id);
|
var releases = await github.Repository.Release.GetAll(repo.Id);
|
||||||
return releases.Select(r => new ModVersionInfo(r.TagName, r.Name ?? r.TagName)).ToArray();
|
return releases.Select(r => new ModVersionInfo(string.IsNullOrWhiteSpace(r.Name) ? r.TagName : r.Name, r.TagName)).ToArray();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,81 +0,0 @@
|
|||||||
using System.Diagnostics.CodeAnalysis;
|
|
||||||
using Unleash;
|
|
||||||
using Unleash.ClientFactory;
|
|
||||||
|
|
||||||
namespace ModpackUpdater.Manager;
|
|
||||||
|
|
||||||
public class ModpackFeatures(ModpackConfig modpackConfig)
|
|
||||||
{
|
|
||||||
private IUnleash? api;
|
|
||||||
private UnleashContext context;
|
|
||||||
private UnleashSettings settings;
|
|
||||||
|
|
||||||
public static string FeatureAllowExtas => "allow-extras";
|
|
||||||
|
|
||||||
~ModpackFeatures()
|
|
||||||
{
|
|
||||||
api?.Dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsEnabled(string feature)
|
|
||||||
{
|
|
||||||
return IsEnabled(feature, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsEnabled(string feature, AppFeatureContext context)
|
|
||||||
{
|
|
||||||
return CheckFeature(feature, context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsInvalid()
|
|
||||||
{
|
|
||||||
return string.IsNullOrWhiteSpace(modpackConfig.UnleashApiUrl) || string.IsNullOrWhiteSpace(modpackConfig.UnleashInstanceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
[MemberNotNullWhen(true, nameof(api))]
|
|
||||||
private bool InitializeApi()
|
|
||||||
{
|
|
||||||
if (api != null
|
|
||||||
|| string.IsNullOrWhiteSpace(modpackConfig.UnleashApiUrl)
|
|
||||||
|| string.IsNullOrWhiteSpace(modpackConfig.UnleashInstanceId))
|
|
||||||
return api != null;
|
|
||||||
|
|
||||||
settings = new UnleashSettings
|
|
||||||
{
|
|
||||||
AppName = "Modpack Updater",
|
|
||||||
UnleashApi = new Uri(modpackConfig.UnleashApiUrl),
|
|
||||||
FetchTogglesInterval = TimeSpan.FromSeconds(0),
|
|
||||||
InstanceTag = modpackConfig.UnleashInstanceId,
|
|
||||||
};
|
|
||||||
|
|
||||||
api = new UnleashClientFactory().CreateClient(settings, synchronousInitialization: true);
|
|
||||||
|
|
||||||
return api != null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool CheckFeature(string name, AppFeatureContext context)
|
|
||||||
{
|
|
||||||
return InitializeApi() && api.IsEnabled(name, GetContext(context));
|
|
||||||
}
|
|
||||||
|
|
||||||
private UnleashContext GetContext(AppFeatureContext ccontext)
|
|
||||||
{
|
|
||||||
context ??= new();
|
|
||||||
context.CurrentTime = DateTime.Now;
|
|
||||||
ccontext?.Apply(context);
|
|
||||||
return context;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public abstract class AppFeatureContext
|
|
||||||
{
|
|
||||||
public abstract void Apply(UnleashContext context);
|
|
||||||
}
|
|
||||||
|
|
||||||
public class AllowExtrasFeatureContext(ModpackInfo info) : AppFeatureContext
|
|
||||||
{
|
|
||||||
public override void Apply(UnleashContext context)
|
|
||||||
{
|
|
||||||
context.UserId = info.ExtrasKey;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -169,9 +169,7 @@ public class ModpackInstaller(ModpackConfig updateConfig, ModpackInfo modpackInf
|
|||||||
foreach (InstallAction iaction in checkResult.Actions)
|
foreach (InstallAction iaction in checkResult.Actions)
|
||||||
{
|
{
|
||||||
var destFilePath = iaction.GetDestPath(modpackInfo.LocalPath);
|
var destFilePath = iaction.GetDestPath(modpackInfo.LocalPath);
|
||||||
var sourceUrl = updateConfig.PreferDirectLinks && !string.IsNullOrWhiteSpace(iaction.SourceUrl)
|
var sourceUrl = iaction.GetSourceUrl(checkResult.LatestVersion, overwriteVersion: OverwriteVersion);
|
||||||
? iaction.GetSourceUrl(checkResult.LatestVersion, overwriteVersion: OverwriteVersion)
|
|
||||||
: await factory.ResolveSourceUrl(iaction, targetVersion: checkResult.LatestVersion, overwriteVersion: OverwriteVersion);
|
|
||||||
|
|
||||||
if (iaction is UpdateAction uaction)
|
if (iaction is UpdateAction uaction)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -9,11 +9,11 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Castle.Core" Version="5.2.1" />
|
<PackageReference Include="Castle.Core" Version="5.2.1" />
|
||||||
<PackageReference Include="CurseForge.APIClient" Version="4.2.0" />
|
<PackageReference Include="CurseForge.APIClient" Version="4.2.0" />
|
||||||
<PackageReference Include="LaunchDarkly.EventSource" Version="5.2.1" />
|
<PackageReference Include="LaunchDarkly.EventSource" Version="5.3.0" />
|
||||||
<PackageReference Include="Modrinth.Net" Version="3.6.0" />
|
<PackageReference Include="Modrinth.Net" Version="3.6.0" />
|
||||||
<PackageReference Include="Octokit" Version="14.0.0" />
|
<PackageReference Include="Octokit" Version="14.0.0" />
|
||||||
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
|
<PackageReference Include="System.IO.Compression.ZipFile" Version="4.3.0" />
|
||||||
<PackageReference Include="Unleash.Client" Version="5.5.3" />
|
<PackageReference Include="Unleash.Client" Version="5.6.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@@ -9,9 +9,7 @@ public class ModpackConfig
|
|||||||
public string? Name { get; set; }
|
public string? Name { get; set; }
|
||||||
public string? UpdateUrl { get; set; }
|
public string? UpdateUrl { get; set; }
|
||||||
public string? InstallUrl { get; set; }
|
public string? InstallUrl { get; set; }
|
||||||
public string? UnleashApiUrl { get; set; }
|
public List<string> ExtrasKeys { get; } = [];
|
||||||
public string? UnleashInstanceId { get; set; }
|
|
||||||
public bool PreferDirectLinks { get; set; }
|
|
||||||
public string? MinecraftVersion { get; set; }
|
public string? MinecraftVersion { get; set; }
|
||||||
public string? RefTag { get; set; }
|
public string? RefTag { get; set; }
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Pilz.Cryptography" Version="2.1.2" />
|
<PackageReference Include="Pilz.Cryptography" Version="2.1.3" />
|
||||||
<PackageReference Include="Pilz.Extensions" Version="2.1.1" />
|
<PackageReference Include="Pilz.Extensions" Version="2.1.2" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
@@ -1,7 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<configuration>
|
<configuration>
|
||||||
<packageSources>
|
<packageSources>
|
||||||
<add key="Pilz" value="https://git.pilzinsel64.de/api/v4/projects/6/packages/nuget/index.json" />
|
<add key="Pilz" value="https://git.pilzinsel64.de/api/packages/Pilz.NET/nuget/index.json" />
|
||||||
<add key="Pilz.Updating" value="https://git.pilzinsel64.de/api/v4/projects/8/packages/nuget/index.json" />
|
|
||||||
</packageSources>
|
</packageSources>
|
||||||
</configuration>
|
</configuration>
|
||||||
@@ -1,3 +1,3 @@
|
|||||||
using Pilz;
|
using Pilz;
|
||||||
|
|
||||||
[assembly: AssemblyAppVersion(AssemblyAppVersionAttribute.EntryAssemblyVersionKey)]
|
[assembly: AssemblyAppVersion]
|
||||||
1
publish-scripts
Submodule
1
publish-scripts
Submodule
Submodule publish-scripts added at fd658bd9d1
@@ -1,6 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
set -e
|
|
||||||
|
|
||||||
for dir in ModpackUpdater.Apps.Client ModpackUpdater.Apps.Client.Gui ModpackUpdater.Apps.Manager; do
|
|
||||||
( cd "$dir" && ./publish.sh "$1" )
|
|
||||||
done
|
|
||||||
Reference in New Issue
Block a user