From 77f26582fee9417bca552a33dbbcbba0bffc8fc4 Mon Sep 17 00:00:00 2001 From: Dexrn ZacAttack Date: Tue, 4 Mar 2025 02:37:50 -0800 Subject: [PATCH] Clean up Packages.cs, also "improved" app logo grabbing + bump ver --- Controls/AppTile.xaml.cs | 48 ++++++++++- Dialogs/AppListDialog.xaml.cs | 1 + Dialogs/ProgressController.cs | 4 +- README.md | 2 + Utils/Packages.cs | 146 ++++++++++++++++++++-------------- Utils/XHandler.cs | 74 +---------------- WinDurango.csproj | 5 +- 7 files changed, 140 insertions(+), 140 deletions(-) diff --git a/Controls/AppTile.xaml.cs b/Controls/AppTile.xaml.cs index 036dad0..7e55302 100644 --- a/Controls/AppTile.xaml.cs +++ b/Controls/AppTile.xaml.cs @@ -109,7 +109,7 @@ namespace WinDurango.UI.Controls { await WinDurangoPatcher.UnpatchPackage(_package, progress); }); - if (!progress.failed) + if (!progress.Failed) { NoticeDialog good = new NoticeDialog($"WinDurango has been uninstalled from package {_Name}", "Uninstalled"); await good.ShowAsync(); @@ -126,7 +126,7 @@ namespace WinDurango.UI.Controls await WinDurangoPatcher.PatchPackage(_package, false, progress); }); - if (!progress.failed) + if (!progress.Failed) { NoticeDialog good = new NoticeDialog($"WinDurango has been installed in package {_Name}", "Installed"); await good.ShowAsync(); @@ -134,6 +134,7 @@ namespace WinDurango.UI.Controls App.MainWindow.ReloadAppList(); } + // TODO: This can probably be improved public AppTile(string familyName) { _familyName = familyName; @@ -152,7 +153,46 @@ namespace WinDurango.UI.Controls _Version = $"{_package.Id.Version.Major.ToString() ?? "U"}.{_package.Id.Version.Minor.ToString() ?? "U"}.{_package.Id.Version.Build.ToString() ?? "U"}.{_package.Id.Version.Revision.ToString() ?? "U"}"; _Logo = _package.Logo; - string ss = Packages.GetSplashScreenPath(_package); + XbManifestInfo xbInfo = _package.GetXbProperties(); + ManifestInfo mfInfo = _package.GetProperties(); + + string ss = String.Empty; + + // TODO: This seems slow. + if (!string.IsNullOrEmpty(mfInfo.SplashScreen)) + { + ss = Path.Combine(_package.InstalledPath, mfInfo.SplashScreen); + // if it doesn't exist it probably has some scale thing + if (!File.Exists(ss)) + { + for (int i = 100; i < 400; i += 100) + { + string path = Path.Combine(_package.InstalledPath, Path.GetDirectoryName(mfInfo.SplashScreen), Path.GetFileNameWithoutExtension(mfInfo.SplashScreen) + $".scale-{i}.png"); + if (File.Exists(path)) + { + ss = path; + break; + } + } + } + } else if (!string.IsNullOrEmpty(mfInfo.WideLogo)) + { + ss = Path.Combine(_package.InstalledPath, mfInfo.WideLogo); + // if it doesn't exist it probably has some scale thing + if (!File.Exists(ss)) + { + for (int i = 100; i < 400; i += 100) + { + string path = Path.Combine(_package.InstalledPath, Path.GetDirectoryName(mfInfo.WideLogo), Path.GetFileNameWithoutExtension(mfInfo.WideLogo) + $".scale-{i}.png"); + if (File.Exists(path)) + { + ss = path; + break; + } + } + } + } + IReadOnlyList appListEntries = null; try { @@ -167,7 +207,7 @@ namespace WinDurango.UI.Controls if (firstAppListEntry == null) Logger.WriteWarning($"Could not get the applist entry of \"{_Name}\""); - if (ss == null || !File.Exists(ss)) + if (String.IsNullOrEmpty(ss) || !File.Exists(ss)) { try { diff --git a/Dialogs/AppListDialog.xaml.cs b/Dialogs/AppListDialog.xaml.cs index e68359e..8e7a9ac 100644 --- a/Dialogs/AppListDialog.xaml.cs +++ b/Dialogs/AppListDialog.xaml.cs @@ -38,6 +38,7 @@ namespace WinDurango.UI.Dialogs foreach (Package pkg in Packages) { // if we already have the package "installed" we will skip it (not show it in the AppListView) + // maybe this behavior should change? if (App.InstalledPackages.GetPackages().Find(p => p.FamilyName == pkg.Id.FamilyName) != null) continue; ListViewItem item = new() { MinWidth = 200 }; diff --git a/Dialogs/ProgressController.cs b/Dialogs/ProgressController.cs index 02ffdd7..0eda20d 100644 --- a/Dialogs/ProgressController.cs +++ b/Dialogs/ProgressController.cs @@ -70,7 +70,7 @@ namespace WinDurango.UI.Dialogs }); } - public bool failed + public bool Failed { get => hasFailed; } @@ -87,7 +87,7 @@ namespace WinDurango.UI.Dialogs { _dialog.DispatcherQueue.TryEnqueue(() => { - _dialog.ShowAsync(); + _ = _dialog.ShowAsync(); }); } diff --git a/README.md b/README.md index 6f291ca..e1bb894 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,7 @@ For building you'll need Visual Studio 2022 with the following: - [X] Scan for already installed EraOS/XUWP stuff - [X] Allow for any existing installed package to be added to the applist - [ ] Built in updater + - [ ] Fitting place for extra xbox-specific info - [ ] Resize content to fit to screen - [X] Allow for search @@ -29,6 +30,7 @@ For building you'll need Visual Studio 2022 with the following: - [X] Fix icon in the titlebar - [ ] Repo contributors on the about screen - [ ] Get Fluent Thin working + - [ ] Use InfoBar for many progress related things (such as registering package, etc) - [ ] Add versioning to the InstalledPackages json (as in versioning the JSON file itself) - [ ] Make the Package stuff not rely on UI so much, handle that somewhere else. - [X] Fix crash when installation errors diff --git a/Utils/Packages.cs b/Utils/Packages.cs index 0628025..ec8e581 100644 --- a/Utils/Packages.cs +++ b/Utils/Packages.cs @@ -1,4 +1,5 @@ -using System; +using Microsoft.Windows.ApplicationModel.DynamicDependency; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -7,6 +8,7 @@ using System.Threading.Tasks; using System.Xml.Linq; using Windows.ApplicationModel; using Windows.Management.Deployment; +using Windows.Networking; using WinDurango.UI.Dialogs; using WinUI3Localizer; using static WinDurango.UI.Localization.Locale; @@ -17,14 +19,35 @@ namespace WinDurango.UI.Utils // this class sucks so much that we literally had to stop bc we didn't know how to rewrite a function and make it still work with the UI stuff // update: this was fixed same commit. #nullable enable + public class ManifestInfo { public string? DisplayName { get; set; } public string? PublisherDisplayName { get; set; } + public string? StoreLogo { get; set; } public string? Logo { get; set; } + public string? WideLogo { get; set; } + public string? SmallLogo { get; set; } public string? Description { get; set; } + public string? SplashScreen { get; set; } + public (string? Name, string? Version)? OSPackageDependency { get; set; } } - public abstract class Packages + + public class XbManifestInfo + { + public string[]? Ratings { get; set; } + public string? TitleId { get; set; } + public string? OsName { get; set; } + public string? ApplicationEnvironment { get; set; } + public bool? IsBackCompat { get; set; } + + public bool IsEra(ManifestInfo mfInfo) + { + return (this.OsName?.Equals("era", StringComparison.OrdinalIgnoreCase) ?? false) || + (mfInfo.OSPackageDependency?.Name == "Microsoft.GameOs"); + } + } + public static class Packages { // TODO: Make these methods not use the GUI, instead just throw an exception and catch it in the area where the method is actually invoked. /// @@ -56,17 +79,69 @@ namespace WinDurango.UI.Utils } XDocument doc = XDocument.Parse(manifest); - XElement? package = doc.Descendants().FirstOrDefault(e => e.Name.LocalName == "Package"); + XElement? defaultTile = doc?.Descendants().FirstOrDefault(e => e.Name.LocalName == "DefaultTile"); + XElement? visualElements = doc?.Descendants().FirstOrDefault(e => e.Name.LocalName == "VisualElements"); - XElement? properties = package?.Descendants().FirstOrDefault(e => e.Name.LocalName == "Properties"); + manifestInfo.WideLogo = defaultTile?.Attribute("WideLogo")?.Value; + manifestInfo.StoreLogo = doc?.Descendants().FirstOrDefault(e => e.Name.LocalName == "Logo")?.Value; + manifestInfo.Logo = visualElements?.Attribute("Logo")?.Value; + manifestInfo.SmallLogo = visualElements?.Attribute("SmallLogo")?.Value; + manifestInfo.DisplayName = doc?.Descendants().FirstOrDefault(e => e.Name.LocalName == "DisplayName")?.Value; + manifestInfo.PublisherDisplayName = doc?.Descendants().FirstOrDefault(e => e.Name.LocalName == "PublisherDisplayName")?.Value; + manifestInfo.Description = doc?.Descendants().FirstOrDefault(e => e.Name.LocalName == "Description")?.Value; + manifestInfo.SplashScreen = doc?.Descendants().FirstOrDefault(e => e.Name.LocalName == "SplashScreen")?.Attribute("Image")?.Value; + manifestInfo.OSPackageDependency = (doc?.Descendants().FirstOrDefault(e => e.Name.LocalName == "OSPackageDependency")?.Attribute("Name")?.Value, doc?.Descendants().FirstOrDefault(e => e.Name.LocalName == "OSPackageDependency")?.Attribute("Version")?.Value); - manifestInfo.Logo = properties?.Descendants().FirstOrDefault(e => e.Name.LocalName == "Logo")?.Value; - manifestInfo.DisplayName = properties?.Descendants().FirstOrDefault(e => e.Name.LocalName == "DisplayName")?.Value; - manifestInfo.PublisherDisplayName = properties?.Descendants().FirstOrDefault(e => e.Name.LocalName == "PublisherDisplayName")?.Value; - manifestInfo.Description = properties?.Descendants().FirstOrDefault(e => e.Name.LocalName == "Description")?.Value; return manifestInfo; } + public static ManifestInfo GetProperties(this Package pkg) + { + string installPath = pkg.InstalledPath; + string manifestPath = Path.Combine(installPath, "AppxManifest.xml"); + + return GetPropertiesFromManifest(manifestPath); + } + + public static XbManifestInfo GetXbProperties(this Package pkg) + { + string installPath = pkg.InstalledPath; + string manifestPath = Path.Combine(installPath, "AppxManifest.xml"); + + return GetXbProperties(manifestPath); + } + + /// + /// Gets Xbox specific properties from the provided AppxManifest + /// + public static XbManifestInfo GetXbProperties(string manifestPath) + { + XbManifestInfo info = new(); + + if (!File.Exists(manifestPath)) + return info; + + string manifest; + using (var stream = File.OpenRead(manifestPath)) + { + var reader = new StreamReader(stream); + manifest = reader.ReadToEnd(); + } + + XDocument doc = XDocument.Parse(manifest); + + info.Ratings = doc?.Descendants().FirstOrDefault(e => e.Name.LocalName == "Ratings")?.Descendants().Select(e => e.Value).ToArray(); + info.TitleId = doc?.Descendants().FirstOrDefault(e => e.Name.LocalName == "XboxLive")?.Attribute("TitleId")?.Value; + info.OsName = doc?.Descendants().FirstOrDefault(e => e.Name.LocalName == "OSName")?.Value; + info.ApplicationEnvironment = doc?.Descendants().FirstOrDefault(e => e.Name.LocalName == "ApplicationEnvironment")?.Value; + bool isBackCompat; + bool.TryParse(doc?.Descendants().FirstOrDefault(e => e.Name.LocalName == "XboxFission")?.Attribute("IsFissionApp")?.Value, out isBackCompat); + + info.IsBackCompat = isBackCompat; + return info; + } + + /// /// Installs an Xbox Package with the folder given to it /// @@ -86,57 +161,6 @@ namespace WinDurango.UI.Utils await InstallPackageAsync(new Uri(mountDir + "\\AppxManifest.xml", UriKind.Absolute), controller, addInstalledPackage); } - /// - /// Gets a Package's splash screen, if none is found... it returns null. - /// - /// - /// It checks the package's AppxManifest for Package.Applications.Application.VisualElements.SplashScreen.Image - /// - public static string GetSplashScreenPath(Package pkg) - { - try - { - string installPath = pkg.InstalledPath; - string manifestPath = Path.Combine(installPath, "AppxManifest.xml"); - - if (!File.Exists(manifestPath)) - return null; - - string manifest; - using (var stream = File.OpenRead(manifestPath)) - { - var reader = new StreamReader(stream); - manifest = reader.ReadToEnd(); - } - - XDocument doc = XDocument.Parse(manifest); - XElement package = doc.Descendants().FirstOrDefault(e => e.Name.LocalName == "Package"); - if (package == null) return null; - - XElement applications = package.Descendants().FirstOrDefault(e => e.Name.LocalName == "Applications"); - if (applications == null) return null; - - XElement application = applications.Descendants().FirstOrDefault(e => e.Name.LocalName == "Application"); - if (application == null) return null; - - XElement visualElements = application.Descendants().FirstOrDefault(e => e.Name.LocalName == "VisualElements"); - if (visualElements == null) return null; - - XElement splashScreen = visualElements.Descendants().FirstOrDefault(e => e.Name.LocalName == "SplashScreen"); - if (splashScreen == null) return null; - - string imagePath = splashScreen.Attribute("Image")?.Value; - if (imagePath == null) return null; - - string splashScreenPath = Path.Combine(installPath, imagePath); - return splashScreenPath; - } - catch - { - return null; - } - } - /// /// Installs a Package with the provided AppxManifest /// @@ -245,7 +269,7 @@ namespace WinDurango.UI.Utils /// /// Gets a Package by it's Family Name /// - public static Package GetPackageByFamilyName(string familyName) + public static Package? GetPackageByFamilyName(string familyName) { var packageManager = new PackageManager(); var packages = packageManager.FindPackagesForUser(null, familyName); @@ -256,7 +280,7 @@ namespace WinDurango.UI.Utils /// /// Gets the most recent installed package /// - public static Package GetMostRecentInstalledPackage() + public static Package? GetMostRecentInstalledPackage() { var sid = WindowsIdentity.GetCurrent().User?.Value; var pm = new PackageManager(); diff --git a/Utils/XHandler.cs b/Utils/XHandler.cs index 5be1020..2fb319c 100644 --- a/Utils/XHandler.cs +++ b/Utils/XHandler.cs @@ -8,84 +8,16 @@ namespace WinDurango.UI.Utils { public class XHandler { - // unused because sucks - public static (string? DisplayName, string? Description, string? SplashScreen, string? SmallLogo, string? WideLogo, string? Logo) GetVisualElementsInfo(Package package) - { - string installPath = package.InstalledPath; - string manifestPath = Path.Combine(installPath, "AppxManifest.xml"); - - if (!File.Exists(manifestPath)) - return (null, null, null, null, null, null); - - string manifest; - using (var stream = File.OpenRead(manifestPath)) - { - var reader = new StreamReader(stream); - manifest = reader.ReadToEnd(); - } - - XDocument doc = XDocument.Parse(manifest); - XElement xmlPackage = doc.Descendants().FirstOrDefault(e => e.Name.LocalName == "Package"); - XElement application = xmlPackage?.Descendants().LastOrDefault(e => e.Name.LocalName == "Application"); - XElement visualElements = application?.Descendants().FirstOrDefault(e => e.Name.LocalName == "VisualElements"); - if (visualElements == null) - return (null, null, null, null, null, null); - - XElement ss = visualElements?.Descendants().FirstOrDefault(e => e.Name.LocalName == "SplashScreen") ?? null; - XElement defaultTile = visualElements?.Descendants().FirstOrDefault(e => e.Name.LocalName == "DefaultTile") ?? null; - - // holy hell this is ew - - string? DisplayName = visualElements?.Attribute("DisplayName")?.Value ?? null; - string? Description = visualElements?.Attribute("Description")?.Value ?? null; - string? SplashScreen = ss?.Attribute("SplashScreen")?.Value ?? null; - string? SmallLogo = visualElements?.Attribute("SmallLogo")?.Value ?? null; - string? WideLogo = defaultTile?.Attribute("WideLogo")?.Value ?? null; - string? Logo = visualElements?.Attribute("Logo")?.Value ?? null; - - return ( - DisplayName == null || DisplayName.StartsWith("ms-resource:") ? null : DisplayName, - Description == null || Description.StartsWith("ms-resource:") ? null : Description, - SplashScreen == null || SplashScreen.StartsWith("ms-resource:") ? null : SplashScreen, - SmallLogo == null || SmallLogo.StartsWith("ms-resource:") ? null : SmallLogo, - WideLogo == null || WideLogo.StartsWith("ms-resource:") ? null : WideLogo, - Logo == null || Logo.StartsWith("ms-resource:") ? null : Logo - ); - - } - public static List GetXPackages(List packages) { // first try implementation and it worked hell yeah List result = []; foreach (Package package in packages) { - string installPath = package.InstalledPath; - string manifestPath = Path.Combine(installPath, "AppxManifest.xml"); - - if (!File.Exists(manifestPath)) - continue; - - string manifest; - using (FileStream stream = File.OpenRead(manifestPath)) - { - StreamReader reader = new(stream); - manifest = reader.ReadToEnd(); - } - - XDocument doc = XDocument.Parse(manifest); - XElement xmlPackage = doc.Descendants().FirstOrDefault(e => e.Name.LocalName == "Package"); - if (xmlPackage == null) continue; - - XElement prerequisites = xmlPackage.Descendants().FirstOrDefault(e => e.Name.LocalName == "Prerequisites"); - XElement dependencies = xmlPackage?.Descendants().FirstOrDefault(e => e.Name.LocalName == "Dependencies"); - XElement osName = prerequisites?.Descendants().FirstOrDefault(e => e.Name.LocalName == "OSName"); - XElement osPackageDependency = dependencies?.Descendants().FirstOrDefault(e => e.Name.LocalName == "OSPackageDependency"); - - if ((osName != null && osName.Value.Equals("era", System.StringComparison.InvariantCultureIgnoreCase)) || (osPackageDependency != null && osPackageDependency.Attribute("Name")?.Value == "Microsoft.GameOs")) - { + XbManifestInfo xbManifestInfo = package.GetXbProperties(); + ManifestInfo manifestInfo = package.GetProperties(); + if (xbManifestInfo.IsEra(manifestInfo)) result.Add(package); - } } Logger.WriteInformation($"Found {result.Count} Era/XbUWP packages"); return result; diff --git a/WinDurango.csproj b/WinDurango.csproj index 7473fa7..c9b7f35 100644 --- a/WinDurango.csproj +++ b/WinDurango.csproj @@ -15,8 +15,8 @@ False Assets\icon.ico 10.0.19041.0 - 0.1.2 - 0.1.2 + 0.1.2.1 + 0.1.2.1 WinDurango UI true @@ -65,6 +65,7 @@ WinDurango https://github.com/WinDurango/WinDurango.UI disable + 0.1.2.1