Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Load and unload UI pages on demand #3204

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions src/UniGetUI.PackageEngine.PackageEngine/PackageBackupHelper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
using UniGetUI.Core.Data;
using UniGetUI.Core.Logging;
using UniGetUI.Core.SettingsEngine;
using UniGetUI.Core.Tools;
using UniGetUI.PackageEngine.Enums;
using UniGetUI.PackageEngine.Interfaces;

namespace UniGetUI.PackageEngine;

public static class PackageBackupHelper
{
public static async Task BackupPackages()
{
try
{
Logger.Debug("Starting package backup");
List<IPackage> packagesToExport = [];
foreach (IPackage package in PEInterface.InstalledPackagesLoader.Packages)
{
packagesToExport.Add(package);
}

string BackupContents = await PEInterface.PackageBundlesLoader.CreateBundle(packagesToExport.ToArray(), BundleFormatType.JSON);

string dirName = Settings.GetValue("ChangeBackupOutputDirectory");
if (dirName == "")
{
dirName = CoreData.UniGetUI_DefaultBackupDirectory;
}

if (!Directory.Exists(dirName))
{
Directory.CreateDirectory(dirName);
}

string fileName = Settings.GetValue("ChangeBackupFileName");
if (fileName == "")
{
fileName = CoreTools.Translate("{pcName} installed packages", new Dictionary<string, object?> { { "pcName", Environment.MachineName } });
}

if (Settings.Get("EnableBackupTimestamping"))
{
fileName += " " + DateTime.Now.ToString("yyyy-MM-dd HH-mm-ss");
}

fileName += ".ubundle";

string filePath = Path.Combine(dirName, fileName);
await File.WriteAllTextAsync(filePath, BackupContents);
Logger.ImportantInfo("Backup saved to " + filePath);
}
catch (Exception ex)
{
Logger.Error("An error occurred while performing a backup");
Logger.Error(ex);
}
}
}
141 changes: 141 additions & 0 deletions src/UniGetUI.PackageEngine.PackageLoader/PackageBundlesLoader.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,13 @@
using System.Text.Json;
using System.Xml.Serialization;
using UniGetUI.Core.Data;
using UniGetUI.Core.Logging;
using UniGetUI.Interface.Enums;
using UniGetUI.PackageEngine.Classes.Serializable;
using UniGetUI.PackageEngine.Enums;
using UniGetUI.PackageEngine.Interfaces;
using UniGetUI.PackageEngine.PackageClasses;
using YamlDotNet.Serialization;

namespace UniGetUI.PackageEngine.PackageLoader
{
Expand Down Expand Up @@ -80,5 +86,140 @@ public void RemoveRange(IEnumerable<IPackage> packages)
}
InvokePackagesChangedEvent();
}

public async Task<string> CreateBundle(IEnumerable<IPackage> unsorted_packages, BundleFormatType formatType = BundleFormatType.JSON)
{
SerializableBundle_v1 exportable = new();
exportable.export_version = 2.1;

List<IPackage> packages = unsorted_packages.ToList();
packages.Sort(Comparison);

int Comparison(IPackage x, IPackage y)
{
if(x.Id != y.Id) return String.Compare(x.Id, y.Id, StringComparison.Ordinal);
if(x.Name != y.Name) return String.Compare(x.Name, y.Name, StringComparison.Ordinal);
return (x.VersionAsFloat > y.VersionAsFloat) ? -1 : 1;
}

foreach (IPackage package in packages)
if (package is Package && !package.Source.IsVirtualManager)
exportable.packages.Add(await Task.Run(package.AsSerializable));
else
exportable.incompatible_packages.Add(package.AsSerializable_Incompatible());

Logger.Debug("Finished loading serializable objects. Serializing with format " + formatType);
string ExportableData;

if (formatType == BundleFormatType.JSON)
ExportableData = JsonSerializer.Serialize(
exportable,
CoreData.SerializingOptions);

else if (formatType == BundleFormatType.YAML)
{
ISerializer serializer = new SerializerBuilder()
.Build();
ExportableData = serializer.Serialize(exportable);
}
else
{
string tempfile = Path.GetTempFileName();
StreamWriter writer = new(tempfile);
XmlSerializer serializer = new(typeof(SerializableBundle_v1));
serializer.Serialize(writer, exportable);
writer.Close();
ExportableData = await File.ReadAllTextAsync(tempfile);
File.Delete(tempfile);
}

Logger.Debug("Serialization finished successfully");

return ExportableData;
}

public async Task<double> AddFromBundle(string RawBundleContent, BundleFormatType format)
{
// Deserialize data
SerializableBundle_v1? DeserializedData;
if (format is BundleFormatType.JSON)
{
DeserializedData = await Task.Run(() => JsonSerializer.Deserialize<SerializableBundle_v1>(RawBundleContent, CoreData.SerializingOptions));
}
else if (format is BundleFormatType.YAML)
{
IDeserializer deserializer =
new DeserializerBuilder()
.IgnoreUnmatchedProperties()
.Build();
DeserializedData = await Task.Run(() => deserializer.Deserialize<SerializableBundle_v1>(RawBundleContent));
}
else
{
string tempfile = Path.GetTempFileName();
await File.WriteAllTextAsync(tempfile, RawBundleContent);
StreamReader reader = new(tempfile);
XmlSerializer serializer = new(typeof(SerializableBundle_v1));
DeserializedData = await Task.Run(() => serializer.Deserialize(reader) as SerializableBundle_v1);
reader.Close();
File.Delete(tempfile);
}

if (DeserializedData is null || DeserializedData.export_version is -1)
{
throw new ArgumentException("DeserializedData was null");
}

List<IPackage> packages = new List<IPackage>();

foreach (SerializablePackage_v1 DeserializedPackage in DeserializedData.packages)
{
packages.Add(PackageFromSerializable(DeserializedPackage));
}

foreach (SerializableIncompatiblePackage_v1 DeserializedPackage in DeserializedData
.incompatible_packages)
{
packages.Add(InvalidPackageFromSerializable(DeserializedPackage, NullSource.Instance));
}

await AddPackagesAsync(packages);

return DeserializedData.export_version;
}

private IPackage PackageFromSerializable(SerializablePackage_v1 raw_package)
{
IPackageManager? manager = null;
IManagerSource? source;

foreach (var possible_manager in Managers)
{
if (possible_manager.Name == raw_package.ManagerName)
{
manager = possible_manager;
break;
}
}

if (manager?.Capabilities.SupportsCustomSources == true)
{
source = manager?.SourcesHelper?.Factory.GetSourceIfExists(raw_package.Source);
}
else
source = manager?.DefaultSource;

if (manager is null || source is null)
{
return InvalidPackageFromSerializable(raw_package.GetInvalidEquivalent(), NullSource.Instance);
}

return new ImportedPackage(raw_package, manager, source);
}

private static IPackage InvalidPackageFromSerializable(SerializableIncompatiblePackage_v1 raw_package, IManagerSource source)
{
return new InvalidImportedPackage(raw_package, source);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,5 +41,6 @@

<ItemGroup>
<PackageReference Include="PhotoSauce.MagicScaler" Version="0.15.0" />
<PackageReference Include="YamlDotNet" Version="16.2.1" />
</ItemGroup>
</Project>
29 changes: 24 additions & 5 deletions src/UniGetUI/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
using Microsoft.Windows.AppLifecycle;
using Microsoft.Windows.AppNotifications;
using UniGetUI.Controls.OperationWidgets;
using UniGetUI.Interface.Enums;
using UniGetUI.PackageEngine.Interfaces;
using UniGetUI.PackageEngine.Managers.PowerShellManager;
using UniGetUI.Pages.DialogPages;
using AbstractOperation = UniGetUI.PackageOperations.AbstractOperation;
using LaunchActivatedEventArgs = Microsoft.UI.Xaml.LaunchActivatedEventArgs;

Expand Down Expand Up @@ -265,23 +267,40 @@ private async Task LoadComponentsAsync()

BackgroundApi.OnShowSharedPackage += (_, package) => MainWindow.DispatcherQueue.TryEnqueue(() =>
{
MainWindow?.NavigationPage?.DiscoverPage.ShowSharedPackage_ThreadSafe(package.Key, package.Value);
DialogHelper.ShowSharedPackage_ThreadSafe(package.Key, package.Value);
MainWindow?.Activate();
});

BackgroundApi.OnUpgradeAll += (_, _) => MainWindow.DispatcherQueue.TryEnqueue(() =>
{
MainWindow?.NavigationPage?.UpdatesPage.UpdateAll();
Logger.Info($"[WIDGETS] Updating ALL packages");

foreach (IPackage package in PEInterface.UpgradablePackagesLoader.Packages)
if (package.Tag is not PackageTag.BeingProcessed and not PackageTag.OnQueue)
Operations.Update(package);
});

BackgroundApi.OnUpgradeAllForManager += (_, manager) => MainWindow.DispatcherQueue.TryEnqueue(() =>
{
MainWindow?.NavigationPage?.UpdatesPage.UpdateAllPackagesForManager(manager);
Logger.Info($"[WIDGETS] Updating all packages with manager={manager}");

foreach (IPackage package in PEInterface.UpgradablePackagesLoader.Packages)
if (package.Tag is not PackageTag.OnQueue and not PackageTag.BeingProcessed)
if (package.Manager.Name == manager || package.Manager.DisplayName == manager)
Operations.Update(package);
});

BackgroundApi.OnUpgradePackage += (_, package) => MainWindow.DispatcherQueue.TryEnqueue(() =>
BackgroundApi.OnUpgradePackage += (_, id) => MainWindow.DispatcherQueue.TryEnqueue(() =>
{
MainWindow?.NavigationPage?.UpdatesPage.UpdatePackageForId(package);
foreach (IPackage package in PEInterface.UpgradablePackagesLoader.Packages)
if (package.Id == id)
{
Operations.Update(package);
Logger.Info($"[WIDGETS] Updating package with id {id}");
return;
}

Logger.Warn($"[WIDGETS] No package with id={id} was found");
});

_ = BackgroundApi.Start();
Expand Down
14 changes: 9 additions & 5 deletions src/UniGetUI/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
using Microsoft.Windows.AppNotifications;
using UniGetUI.Core.Classes;
using UniGetUI.Interface.Enums;
using UniGetUI.Interface.SoftwarePages;
using UniGetUI.PackageEngine.PackageClasses;
using UniGetUI.Pages.DialogPages;

Expand Down Expand Up @@ -159,7 +160,9 @@ public void HandleNotificationActivation(AppNotificationActivatedEventArgs args)

if (action == NotificationArguments.UpdateAllPackages)
{
NavigationPage.UpdatesPage.UpdateAll();
foreach (IPackage package in PEInterface.UpgradablePackagesLoader.Packages)
if (package.Tag is not PackageTag.BeingProcessed and not PackageTag.OnQueue)
MainApp.Operations.Update(package);
}
else if (action == NotificationArguments.ShowOnUpdatesTab)
{
Expand Down Expand Up @@ -253,11 +256,11 @@ private void HandleDeepLink(string link)
if (Id != "" && CombinedManagerName != "" && ManagerName == "" && SourceName == "")
{
Logger.Warn($"URI {link} follows old scheme");
NavigationPage.DiscoverPage.ShowSharedPackage_ThreadSafe(Id, CombinedManagerName);
DialogHelper.ShowSharedPackage_ThreadSafe(Id, CombinedManagerName);
}
else if (Id != "" && ManagerName != "" && SourceName != "")
{
NavigationPage.DiscoverPage.ShowSharedPackage_ThreadSafe(Id, ManagerName, SourceName);
DialogHelper.ShowSharedPackage_ThreadSafe(Id, ManagerName, SourceName);
}
else
{
Expand Down Expand Up @@ -330,8 +333,9 @@ public void ProcessCommandLineParameters()
{
// Handle potential JSON files
Logger.ImportantInfo("Begin attempt to open the package bundle " + param);
NavigationPage.NavigateTo(PageType.Bundles);
_ = NavigationPage.BundlesPage.OpenFromFile(param);

var page = NavigationPage.RequestPageIntoView<PackageBundlesPage>(PageType.Bundles);
_ = page.OpenFromFile(param);
}
else if (param.EndsWith("UniGetUI.exe") || param.EndsWith("UniGetUI.dll"))
{
Expand Down
Loading
Loading