Install confirmation + fix existing applist crash + start on localization

This commit is contained in:
ZacAttack
2024-09-29 20:46:59 -07:00
parent 43f1aa5e0b
commit 8b1e57315d
21 changed files with 824 additions and 76 deletions

View File

@@ -3,14 +3,21 @@ using System;
using System.Diagnostics;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using Windows.Storage;
using WinDurango.UI.Settings;
using WinDurango.UI.Utils;
using WinUI3Localizer;
namespace WinDurango.UI
{
public partial class App : Application
{
private static readonly FileVersionInfo Fvi = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location);
// constants
public static readonly string DataDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "WinDurango");
public static readonly string AppDir = AppContext.BaseDirectory;
private static readonly FileVersionInfo Fvi = FileVersionInfo.GetVersionInfo(Assembly.GetExecutingAssembly().Location);
// versioning
public static readonly uint Major = (uint)Fvi.ProductMajorPart;
public static readonly uint Minor = (uint)Fvi.ProductMinorPart;
public static readonly uint Patch = (uint)Fvi.ProductBuildPart;
@@ -19,6 +26,8 @@ namespace WinDurango.UI
: "HASHFAIL";
public static readonly uint VerPacked = (Major << 22) | (Minor << 12) | Patch;
public static readonly string Version = $"{Fvi.ProductMajorPart}.{Fvi.ProductMinorPart}.{Fvi.ProductBuildPart}_{Hash}"; // 1.0 will be when bugs are squashed and everything works correctly.
// other
public static readonly WdSettings Settings = new();
public static readonly MainWindow MainWindow = new();
public static (uint major, uint minor, uint patch) UnpackVersion(uint verPacked)
@@ -30,13 +39,39 @@ namespace WinDurango.UI
return (major, minor, patch);
}
private async Task InitializeLocalizer()
{
string StringsFolderPath = Path.Combine(AppContext.BaseDirectory, "Strings");
StorageFolder stringsFolder = await StorageFolder.GetFolderFromPathAsync(StringsFolderPath);
ILocalizer localizer = await new LocalizerBuilder()
.AddStringResourcesFolderForLanguageDictionaries(StringsFolderPath)
.SetOptions(options =>
{
options.DefaultLanguage = "en-US";
})
.Build();
}
private void App_UnhandledException(object sender, Microsoft.UI.Xaml.UnhandledExceptionEventArgs e)
{
Logger.WriteException($"{e.Exception.GetType().FullName}: {e.Exception.Message}");
}
public App()
{
this.UnhandledException += App_UnhandledException;
InitializeComponent();
}
protected override void OnLaunched(LaunchActivatedEventArgs args)
public static void OnClosed(object sender, WindowEventArgs args)
{
Logger.WriteInformation("Exiting");
}
protected override async void OnLaunched(LaunchActivatedEventArgs args)
{
await InitializeLocalizer();
Logger.WriteDebug("Showing MainWindow");
MainWindow.Activate();
}

View File

@@ -23,6 +23,7 @@ namespace WinDurango.UI.Controls
private string _Name;
private string _Publisher;
private string _Version;
private Uri _Logo;
private async void HandleUnregister(object sender, SplitButtonClickEventArgs e)
{
@@ -56,12 +57,27 @@ namespace WinDurango.UI.Controls
this.InitializeComponent();
_package = Packages.GetPackageByFamilyName(_familyName);
_Name = _package.DisplayName ?? _package.Id.Name;
try
{
_Name = _package.DisplayName ?? _package.Id.Name;
}
catch
{
_Name = _package.Id.Name;
}
_Publisher = _package.PublisherDisplayName ?? _package.Id.PublisherId;
_Version = $"{_package.Id.Version.Major.ToString() ?? "U"}.{_package.Id.Version.Minor.ToString() ?? "U"}.{_package.Id.Version.Build.ToString() ?? "U"}";
string ss = Packages.getSplashScreenPath(_package);
IReadOnlyList<AppListEntry> appListEntries = _package.GetAppListEntries();
AppListEntry firstAppListEntry = appListEntries.FirstOrDefault();
_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);
IReadOnlyList<AppListEntry> appListEntries = null;
try
{
appListEntries = _package.GetAppListEntries();
} catch
{
Logger.WriteWarning($"Could not get the applist entries of \"{_Name}\"");
}
AppListEntry firstAppListEntry = appListEntries?.FirstOrDefault() ?? null;
if (firstAppListEntry == null)
Logger.WriteWarning($"Could not get the applist entry of \"{_Name}\"");
@@ -80,13 +96,13 @@ namespace WinDurango.UI.Controls
}
else
{
BitmapImage logoImage = new(_package.Logo);
BitmapImage logoImage = new(_Logo);
appLogo.Source = logoImage;
}
}
catch (Exception)
{
BitmapImage logoImage = new(_package.Logo);
BitmapImage logoImage = new(_Logo);
appLogo.Source = logoImage;
}
}

View File

@@ -9,23 +9,7 @@
SecondaryButtonText="Cancel"
SecondaryButtonClick="hideDialog">
<Grid>
<ListView Name="appListView" ItemsSource="{x:Bind Pkgs}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<!-- This ups the crash chance by a whole lot.
<Image Width="64" Height="64" Margin="5" ImageFailed="logoFailed">
<Image.Source>
<BitmapImage UriSource="{Binding Logo, TargetNullValue='ms-appx:///Assets/testimg.png', FallbackValue='ms-appx:///Assets/testimg.png'}" />
</Image.Source>
</Image> -->
<StackPanel Orientation="Vertical" Margin="5">
<TextBlock Text="{Binding DisplayName, TargetNullValue='Unknown', FallbackValue='Unknown'}" FontWeight="Bold" />
<TextBlock Text="{Binding PublisherDisplayName, TargetNullValue='Unknown', FallbackValue='Unknown'}" />
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
<ListView x:Name="appListView" Loaded="AppListView_Loaded">
</ListView>
</Grid>
</ContentDialog>

View File

@@ -1,8 +1,10 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Text;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media.Imaging;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Windows.ApplicationModel;
using WinDurango.UI.Settings;
using WinDurango.UI.Utils;
@@ -16,8 +18,6 @@ namespace WinDurango.UI.Dialogs
public AppListDialog(List<Package> packages, bool multiSelect = false)
{
Logger.WriteWarning($"AppList is very buggy atm, expect a crash.");
this.Pkgs = packages;
this.DataContext = this;
@@ -30,8 +30,73 @@ namespace WinDurango.UI.Dialogs
}
private void AppListView_Loaded(object sender, RoutedEventArgs e)
{
var listView = (ListView)sender;
private void logoFailed(object sender, ExceptionRoutedEventArgs e)
foreach (var pkg in Pkgs)
{
var item = new ListViewItem();
item.MinWidth = 200;
var stackPanel = new StackPanel
{
Orientation = Orientation.Horizontal
};
var packageLogo = new Image
{
Width = 64,
Height = 64,
Margin = new Thickness(5),
Source = new BitmapImage(pkg.Logo ?? new Uri("ms-appx:///Assets/testimg.png"))
};
packageLogo.ImageFailed += LogoFailed;
var packageInfo = new StackPanel
{
Orientation = Orientation.Vertical,
Margin = new Thickness(5)
};
string displayName;
try
{
displayName = pkg.DisplayName;
}
catch (System.Runtime.InteropServices.COMException)
{
displayName = pkg.Id.Name;
}
var packageName = new TextBlock
{
Text = displayName ?? "Unknown",
FontWeight = FontWeights.Bold
};
var publisherName = new TextBlock
{
Text = pkg.PublisherDisplayName ?? "Unknown"
};
packageInfo.Children.Add(packageName);
packageInfo.Children.Add(publisherName);
stackPanel.Children.Add(packageLogo);
stackPanel.Children.Add(packageInfo);
item.Content = stackPanel;
item.Tag = pkg;
listView.Items.Add(item);
}
}
private void LogoFailed(object sender, ExceptionRoutedEventArgs e)
{
var image = sender as Image;
image.Source = new BitmapImage(new Uri("ms-appx:///Assets/testimg.png"));
@@ -40,12 +105,17 @@ namespace WinDurango.UI.Dialogs
private void AddToAppList(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
foreach (Package package in appListView.SelectedItems)
foreach (ListViewItem listViewItem in appListView.SelectedItems)
{
if (InstalledPackages.GetInstalledPackage(package.Id.FamilyName) == null)
InstalledPackages.AddInstalledPackage(package);
App.MainWindow.AppsListPage.InitAppList();
var package = listViewItem.Tag as Package;
if (package != null && package?.Id?.FamilyName != null)
{
if (InstalledPackages.GetInstalledPackage(package.Id.FamilyName) == null)
InstalledPackages.AddInstalledPackage(package);
}
}
App.MainWindow.AppsListPage.InitAppList();
}
private void hideDialog(ContentDialog sender, ContentDialogButtonClickEventArgs args)

View File

@@ -0,0 +1,22 @@
<ContentDialog
x:Class="WinDurango.UI.Dialogs.InstallConfirmationDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:WinDurango.UI.Dialogs"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="Confirm install"
Style="{ThemeResource DefaultContentDialogStyle}"
PrimaryButtonText="Install"
SecondaryButtonText="Cancel">
<Grid>
<StackPanel Orientation="Horizontal">
<Image Name="packageLogo" MaxHeight="128" MaxWidth="128"></Image>
<StackPanel Margin="10 0 0 0" Orientation="Vertical">
<TextBlock Name="packageName" FontWeight="Bold" FontSize="18" TextWrapping="Wrap" MaxWidth="400"></TextBlock>
<TextBlock Name="packagePublisher" TextWrapping="Wrap" MaxWidth="400"></TextBlock>
<TextBlock Name="packageVersion" TextWrapping="Wrap" MaxWidth="400"></TextBlock>
<TextBlock Name="packageLocation" TextWrapping="Wrap" MaxWidth="400"></TextBlock>
</StackPanel>
</StackPanel>
</Grid>
</ContentDialog>

View File

@@ -0,0 +1,43 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
using Microsoft.UI.Xaml.Navigation;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using WinDurango.UI.Utils;
namespace WinDurango.UI.Dialogs
{
public sealed partial class InstallConfirmationDialog : ContentDialog
{
public InstallConfirmationDialog(string manifest)
{
var properties = Packages.GetPropertiesFromManifest(manifest);
string manifestFolder = manifest.Substring(0, manifest.Length - "AppxManifest.xml".Length);
this.InitializeComponent();
this.XamlRoot = App.MainWindow.Content.XamlRoot;
packageName.Text = properties.DisplayName ?? "Unknown";
packagePublisher.Text = properties.PublisherDisplayName ?? "Unknown";
packageVersion.Text = "Unknown";
packageLocation.Text = manifest;
packageLogo.Source = new BitmapImage(new Uri(Path.Combine(manifestFolder, properties.Logo)));
}
private void ContentDialog_PrimaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
}
private void ContentDialog_SecondaryButtonClick(ContentDialog sender, ContentDialogButtonClickEventArgs args)
{
}
}
}

16
Localization/Locale.cs Normal file
View File

@@ -0,0 +1,16 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using WinDurango.UI.Utils;
using WinUI3Localizer;
namespace WinDurango.UI.Localization
{
public static class Locale
{
public static string GetLocalizedText(string name, params object[] args)
{
return string.Format(name.GetLocalizedString(), args);
}
}
}

View File

@@ -15,7 +15,7 @@ namespace WinDurango.UI
public sealed partial class MainWindow : Window
{
public readonly string AppName = "WinDurango";
public static readonly WdSettings Settings = new();
public static readonly WdSettings Settings = App.Settings;
public AppsListPage AppsListPage;
public SettingsPage SettingsPage;
public AboutPage AboutPage;
@@ -89,6 +89,7 @@ namespace WinDurango.UI
public MainWindow()
{
Closed += App.OnClosed;
Title = AppName;
AppWindow.SetIcon("ms-appx:///Assets/icon.ico");
this.Activate();

View File

@@ -6,8 +6,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:appLocal="using:WinDurango.UI"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:controls="using:WinDurango.UI.Controls" xmlns:svg="using:SVGImage.SVG"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
mc:Ignorable="d">
<StackPanel Orientation="Vertical" Padding="10">
<TextBlock Text="Application Info" FontSize="24"/>

View File

@@ -1,10 +1,14 @@
using Microsoft.UI.Xaml;
using CommunityToolkit.WinUI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.WebSockets;
using System.Security.Principal;
using System.Threading.Tasks;
using Windows.Management.Deployment;
using Windows.Storage;
using Windows.Storage.Pickers;
@@ -12,6 +16,7 @@ using WinDurango.UI.Controls;
using WinDurango.UI.Dialogs;
using WinDurango.UI.Settings;
using WinDurango.UI.Utils;
using static WinDurango.UI.Localization.Locale;
namespace WinDurango.UI.Pages
{
@@ -43,7 +48,7 @@ namespace WinDurango.UI.Pages
private async void ShowAppListView(object sender, RoutedEventArgs e)
{
AppListDialog dl = new(Packages.GetInstalledPackages().ToList());
AppListDialog dl = new(Packages.GetInstalledPackages().ToList(), true);
dl.Title = "Installed UWP apps";
dl.XamlRoot = this.Content.XamlRoot;
await dl.ShowAsync();
@@ -51,7 +56,7 @@ namespace WinDurango.UI.Pages
private async void ShowInstalledEraApps(object sender, RoutedEventArgs e)
{
AppListDialog dl = new(XHandler.getXPackages(Packages.GetInstalledPackages().ToList()), true);
AppListDialog dl = new(XHandler.GetXPackages(Packages.GetInstalledPackages().ToList()), true);
dl.Title = "Installed Era/XUWP apps";
dl.XamlRoot = this.Content.XamlRoot;
await dl.ShowAsync();
@@ -69,7 +74,15 @@ namespace WinDurango.UI.Pages
{
InitializeComponent();
Stopwatch PlatinumWatch = new Stopwatch();
Logger.WriteDebug("Initializing AppsListPage...");
PlatinumWatch.Start();
InitAppList();
PlatinumWatch.Stop();
Logger.WriteDebug("Initialized AppsListPage in {0:D2}:{1:D2}:{2:D2}.{3:D3}", (int)PlatinumWatch.Elapsed.TotalHours, (int)PlatinumWatch.Elapsed.TotalMinutes, (int)PlatinumWatch.Elapsed.TotalSeconds, (int)PlatinumWatch.Elapsed.TotalMilliseconds);
}
private async void InstallButton_Tapped(SplitButton sender, SplitButtonClickEventArgs args)
@@ -93,7 +106,12 @@ namespace WinDurango.UI.Pages
if (File.Exists(manifest))
{
_ = await Packages.InstallPackageAsync(new Uri(manifest, UriKind.Absolute), (bool)addToAppListCheckBox.IsChecked);
var dialog = new InstallConfirmationDialog(manifest);
dialog.PrimaryButtonClick += async (sender, e) =>
{
_ = await Packages.InstallPackageAsync(new Uri(manifest, UriKind.Absolute), (bool)addToAppListCheckBox.IsChecked);
};
await dialog.ShowAsync();
}
else
{
@@ -103,19 +121,24 @@ namespace WinDurango.UI.Pages
// there IS a mount folder
if (File.Exists(Path.Combine(mountFolder + "\\AppxManifest.xml")))
{
await Packages.InstallXPackageAsync(folder.Path.ToString(), autoSymlinkCheckBox.IsEnabled && (bool)autoSymlinkCheckBox.IsChecked ? Packages.XvdMode.CreateSymlinks : Packages.XvdMode.DontUse, (bool)addToAppListCheckBox.IsChecked);
var dialog = new InstallConfirmationDialog(Path.Combine(mountFolder + "\\AppxManifest.xml"));
dialog.PrimaryButtonClick += async (sender, e) =>
{
await Packages.InstallXPackageAsync(folder.Path.ToString(), autoSymlinkCheckBox.IsEnabled && (bool)autoSymlinkCheckBox.IsChecked ? Packages.XvdMode.CreateSymlinks : Packages.XvdMode.DontUse, (bool)addToAppListCheckBox.IsChecked);
};
await dialog.ShowAsync();
}
else
{
// there is no AppxManifest inside.
Logger.WriteError($"Could not find AppxManifest.xml in {folder.Path} and {mountFolder}");
await new NoticeDialog($"AppxManifest does not exist in both {folder.Path} and {mountFolder}", "Error").Show();
await new NoticeDialog(GetLocalizedText("ManifestNotFoundMulti", folder.Path, mountFolder), "Error").Show();
}
}
else
{
Logger.WriteError($"Could not find AppxManifest.xml in {folder.Path} and no Mount folder exists");
await new NoticeDialog($"AppxManifest does not exist in {folder.Path} and there is no \"Mount\" folder.", "Error").Show();
await new NoticeDialog(GetLocalizedText("ManifestNotFoundNoMount", folder.Path), "Error").Show();
}
return;

View File

@@ -5,8 +5,7 @@
xmlns:local="using:WinDurango.UI.Pages"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
mc:Ignorable="d">
<Grid Padding="10 10 10 10">
<StackPanel Grid.Row="1">
@@ -28,6 +27,7 @@
</DropDownButton.Flyout>
</DropDownButton>
<TextBlock Margin="0 5 0 5" Text="Other"/>
<ToggleSwitch OnContent="Enable debug logging" OffContent="Enable debug logging" Toggled="OnDebugLogToggled" Name="DebugLogToggle" Loaded="OnDebugLogToggleLoaded"/>
<Button Name="appdataButton" Margin="0 5 0 5" Click="OpenAppData">Open WinDurango AppData folder</Button>
</StackPanel>
</Grid>

View File

@@ -1,6 +1,7 @@
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using System.Diagnostics;
using System.Windows.Controls.Primitives;
using WinDurango.UI.Settings;
namespace WinDurango.UI.Pages
@@ -10,36 +11,52 @@ namespace WinDurango.UI.Pages
// should probably merge these into one?
private async void OnMicaSelected(object sender, RoutedEventArgs e)
{
await MainWindow.Settings.SetSetting("Theme", WdSettingsData.ThemeSetting.Mica);
await App.Settings.SetSetting("Theme", WdSettingsData.ThemeSetting.Mica);
OnThemeButtonLoaded(sender, e);
}
private async void OnMicaAltSelected(object sender, RoutedEventArgs e)
{
await MainWindow.Settings.SetSetting("Theme", WdSettingsData.ThemeSetting.MicaAlt);
await App.Settings.SetSetting("Theme", WdSettingsData.ThemeSetting.MicaAlt);
OnThemeButtonLoaded(sender, e);
}
private async void OnFluentSelected(object sender, RoutedEventArgs e)
{
await MainWindow.Settings.SetSetting("Theme", WdSettingsData.ThemeSetting.Fluent);
await App.Settings.SetSetting("Theme", WdSettingsData.ThemeSetting.Fluent);
OnThemeButtonLoaded(sender, e);
}
private async void OnSystemSelected(object sender, RoutedEventArgs e)
{
await MainWindow.Settings.SetSetting("Theme", WdSettingsData.ThemeSetting.System);
await App.Settings.SetSetting("Theme", WdSettingsData.ThemeSetting.System);
OnThemeButtonLoaded(sender, e);
}
private async void OnDebugLogToggled(object sender, RoutedEventArgs e)
{
await App.Settings.SetSetting("DebugLoggingEnabled", (sender as ToggleSwitch).IsOn);
}
private void OpenAppData(object sender, RoutedEventArgs e)
{
Process.Start(new ProcessStartInfo(App.DataDir) { UseShellExecute = true });
}
private void OnDebugLogToggleLoaded(object sender, RoutedEventArgs e)
{
if (Debugger.IsAttached)
{
(sender as ToggleSwitch).IsEnabled = false;
(sender as ToggleSwitch).IsOn = true;
(sender as ToggleSwitch).OnContent = "Enable debug logging (currently debugging)";
}
}
private void OnThemeButtonLoaded(object sender, RoutedEventArgs e)
{
switch (MainWindow.Settings.Settings.Theme)
switch (App.Settings.Settings.Theme)
{
case WdSettingsData.ThemeSetting.Fluent:
themeButton.Content = "Fluent";

View File

@@ -14,15 +14,16 @@ GUI for WinDurango, which is planned to allow for easy installing/patching among
- [X] Allow for package removal from UI instead of just completely uninstalling.
- [X] Installation options
- [X] Scan for already installed EraOS/XUWP stuff
- [ ] Allow for any existing installed package to be added to the applist
- [X] Allow for any existing installed package to be added to the applist
- [ ] Resize content to fit to screen
- [ ] Allow for search
## Bugs/Improvements
- [X] Make the applist not go offscreen (lol)
- [ ] Once we have enough settings in place, make it have pages using a horizontal NavigationView (probably)
- [ ] Applist pages
- [ ] Fix icon in the titlebar
- [ ] Fix UI load speed when loading a lot of packages on startup
- [X] Applist scrolling
- [X] Fix icon in the titlebar
- [ ] Repo contributors on the about screen
- [ ] Get Fluent Thin working
- [ ] Add versioning to the InstalledPackages json (as in versioning the JSON file itself)

View File

@@ -3,6 +3,7 @@ using System.IO;
using System.Reflection;
using System.Text.Json;
using System.Threading.Tasks;
using WinDurango.UI.Dialogs;
using WinDurango.UI.Utils;
namespace WinDurango.UI.Settings;
@@ -20,6 +21,7 @@ public class WdSettingsData
public uint SaveVersion { get; set; } = App.VerPacked;
public ThemeSetting Theme { get; set; } = ThemeSetting.Fluent;
public bool DebugLoggingEnabled { get; set; } = false;
}
public class WdSettings
@@ -44,8 +46,7 @@ public class WdSettings
{
if (loadedSettings.SaveVersion > App.VerPacked)
{
BackupSettings();
GenerateSettings();
ResetSettings();
Logger.WriteInformation($"Settings were reset due to the settings file version being too new. ({loadedSettings.SaveVersion})");
}
loadedSettings = JsonSerializer.Deserialize<WdSettingsData>(json);
@@ -65,6 +66,13 @@ public class WdSettings
}
}
private void ResetSettings()
{
BackupSettings();
GenerateSettings();
Logger.WriteInformation($"Settings have been reset");
}
private void BackupSettings()
{
string settingsBackup = _settingsFile + ".old_" + ((DateTimeOffset)DateTime.UtcNow).ToUnixTimeMilliseconds().ToString();

126
Strings/en-US/Controls.resw Normal file
View File

@@ -0,0 +1,126 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="EDbgLog" xml:space="preserve">
<value>Enable debug logging</value>
</data>
<data name="DDbgLog" xml:space="preserve">
<value>Disable debug logging</value>
</data>
</root>

143
Strings/en-US/Errors.resw Normal file
View File

@@ -0,0 +1,143 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ManifestNotFoundNoMount" xml:space="preserve">
<value>AppxManifest does not exist in {0} and there is no "Mount" folder.</value>
<comment>for when AppxManifest.xml is not found and there is no Mount folder to look in</comment>
</data>
<data name="MountNotFound" xml:space="preserve">
<value>{0} was not found.</value>
</data>
<data name="ManifestNotFoundMulti" xml:space="preserve">
<value>AppxManifest does not exist in {0} and {1}</value>
<comment>for when it's not found in either the Mount folder or current chosen folder</comment>
</data>
<data name="NotFound" xml:space="preserve">
<value>{0} was not found.</value>
</data>
<data name="AlreadyInstalled" xml:space="preserve">
<value>{0} is already installed.</value>
</data>
<data name="PackageInstallFailedEx" xml:space="preserve">
<value>{0} failed to install: {1}</value>
</data>
<data name="PackageUninstallFailedEx" xml:space="preserve">
<value>Failed to uninstall {0}: {1}</value>
</data>
</root>

View File

@@ -0,0 +1,144 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ReadingManifest" xml:space="preserve">
<value>Reading manifest...</value>
</data>
<data name="CheckingInstallStatus" xml:space="preserve">
<value>Checking if {0} is already installed...</value>
</data>
<data name="InstallingPackage" xml:space="preserve">
<value>Installing {0}...</value>
</data>
<data name="GettingAppInfo" xml:space="preserve">
<value>Getting app info...</value>
</data>
<data name="UpdatingAppList" xml:space="preserve">
<value>Updating app list...</value>
</data>
<data name="PackageInstalled" xml:space="preserve">
<value>{0} was installed! :)</value>
</data>
<data name="UninstallingPackage" xml:space="preserve">
<value>Uninstalling {0}...</value>
</data>
<data name="PackageUninstalled" xml:space="preserve">
<value>{0} was uninstalled.</value>
</data>
</root>

View File

@@ -40,8 +40,16 @@ namespace WinDurango.UI.Utils
throw e;
}
public static void WriteException(string str)
{
Instance.WriteLog(LogLevel.Exception, str);
}
private void WriteLog(LogLevel level, string message)
{
if (level == LogLevel.Debug && !App.Settings.Settings.DebugLoggingEnabled && !Debugger.IsAttached)
return;
string logEntry = $"[{DateTime.Now:yyyy-MM-dd HH:mm:ss.fff}] [{level.ToString().ToUpper()}] {message}";
Debug.WriteLine(logEntry);

View File

@@ -9,7 +9,8 @@ using Windows.ApplicationModel;
using Windows.Management.Deployment;
using WinDurango.UI.Dialogs;
using WinDurango.UI.Settings;
using WinUI3Localizer;
using static WinDurango.UI.Localization.Locale;
namespace WinDurango.UI.Utils
{
@@ -24,6 +25,32 @@ namespace WinDurango.UI.Utils
return pm.FindPackagesForUser(sid);
}
public static (string? DisplayName, string? PublisherDisplayName, string? Logo, string? Description) GetPropertiesFromManifest(string manifestPath)
{
if (!File.Exists(manifestPath))
return (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 package = doc.Descendants().FirstOrDefault(e => e.Name.LocalName == "Package");
if (package == null) return (null, null, null, null);
XElement properties = package.Descendants().FirstOrDefault(e => e.Name.LocalName == "Properties");
if (properties == null) return (null, null, null, null);
string logo = properties?.Descendants().FirstOrDefault(e => e.Name.LocalName == "Logo").Value ?? null;
string displayName = properties?.Descendants().FirstOrDefault(e => e.Name.LocalName == "DisplayName").Value ?? null;
string publisherDisplayName = properties?.Descendants().FirstOrDefault(e => e.Name.LocalName == "PublisherDisplayName").Value ?? null;
string description = properties?.Descendants()?.FirstOrDefault(e => e.Name.LocalName == "Description")?.Value ?? null;
return (displayName, publisherDisplayName, logo, description);
}
public enum XvdMode
{
CreateSymlinks,
@@ -39,7 +66,7 @@ namespace WinDurango.UI.Utils
if (!Directory.Exists(mountDir))
{
await new NoticeDialog($"{mountDir} was not found.", "Error").Show();
await new NoticeDialog(GetLocalizedText($"mountNotFound", mountDir), "Error").Show();
return;
}
@@ -66,10 +93,9 @@ namespace WinDurango.UI.Utils
}
}
public static string getSplashScreenPath(Package pkg)
public static string GetSplashScreenPath(Package pkg)
{
try
{
try {
string installPath = pkg.InstalledPath;
string manifestPath = Path.Combine(installPath, "AppxManifest.xml");
@@ -119,7 +145,7 @@ namespace WinDurango.UI.Utils
// TODO: strip UI
if (!File.Exists(manifestPath))
{
await new NoticeDialog($"{manifestPath} was not found.", "Error").Show();
await new NoticeDialog(GetLocalizedText("NotFound", manifestPath), "Error").Show();
return null;
}
@@ -131,7 +157,7 @@ namespace WinDurango.UI.Utils
try
{
Logger.WriteInformation($"Reading manifest...");
status.Text = "Reading manifest...";
status.Text = "ReadingManifest".GetLocalizedString();
string manifest;
await using (var stream = File.OpenRead(manifestPath))
{
@@ -147,7 +173,7 @@ namespace WinDurango.UI.Utils
string pkgPublisher = identity.Attribute("Publisher")?.Value;
status.Progress = 20.0;
status.Text = $"Checking if {pkgName} is already installed...";
status.Text = GetLocalizedText("CheckingInstallStatus", pkgName);
var sid = WindowsIdentity.GetCurrent().User?.Value;
var installedPackages = await Task.Run(() => pm.FindPackagesForUser(sid, pkgName, pkgPublisher));
@@ -155,24 +181,24 @@ namespace WinDurango.UI.Utils
{
status.Hide();
Logger.WriteError($"{pkgName} is already installed.");
await new NoticeDialog($"{pkgName} is already installed.", "Error").Show();
await new NoticeDialog(GetLocalizedText("AlreadyInstalled", pkgName), "Error").Show();
return null;
}
status.Progress = 40.0;
status.Text = $"Installing {pkgName}...";
status.Text = GetLocalizedText("InstallingPackage", pkgName);
Logger.WriteInformation($"Registering...");
var deployment = await pm.RegisterPackageAsync(appxManifestUri, null, DeploymentOptions.DevelopmentMode);
status.Progress = 60.0;
status.Text = $"Getting app info...";
status.Text = "GettingAppInfo".GetLocalizedString();
var recentPkg = GetMostRecentlyInstalledPackage();
if (addInstalledPackage)
{
status.Text = $"Updating app list...";
status.Text = $"UpdatingAppList".GetLocalizedString();
status.Progress = 80.0;
InstalledPackages.AddInstalledPackage(recentPkg);
status.Progress = 90.0;
@@ -186,7 +212,7 @@ namespace WinDurango.UI.Utils
status.Hide();
Logger.WriteInformation($"{recentPkg.Id.Name} was installed.");
await new NoticeDialog($"{recentPkg.Id.Name} was installed! :)").Show();
await new NoticeDialog(GetLocalizedText("PackageInstalled", recentPkg.Id.Name)).Show();
return recentPkg.Id.FamilyName;
}
catch (Exception e)
@@ -195,7 +221,7 @@ namespace WinDurango.UI.Utils
status.Hide();
Logger.WriteError($"{appxManifestUri} failed to install");
Logger.WriteException(e);
await new NoticeDialog($"{appxManifestUri} failed to install: {e.Message}", "Error").Show();
await new NoticeDialog(GetLocalizedText("PackageInstallFailedEx", appxManifestUri, e.Message), "Error").Show();
return null;
}
}
@@ -203,7 +229,7 @@ namespace WinDurango.UI.Utils
public static async Task RemovePackage(Package package)
{
Logger.WriteError($"Uninstalling {package.DisplayName}...");
var status = new ProgressDialog($"Uninstalling {package.DisplayName}...", "Uninstalling", false);
var status = new ProgressDialog(GetLocalizedText("UninstallingPackage", package.DisplayName), "Uninstalling", false);
_ = App.MainWindow.DispatcherQueue.TryEnqueue(async () => await status.ShowAsync());
PackageManager pm = new();
try
@@ -214,8 +240,8 @@ namespace WinDurango.UI.Utils
InstalledPackages.RemoveInstalledPackage(package);
status.Progress = 100.0;
status.Hide();
Logger.WriteError($"{package.DisplayName} was uninstalled.");
await new NoticeDialog($"{package.DisplayName} was uninstalled.").Show();
Logger.WriteInformation($"{package.DisplayName} was uninstalled.");
await new NoticeDialog(GetLocalizedText("PackageUninstalled", package.DisplayName)).Show();
App.MainWindow.ReloadAppList();
}
catch (Exception ex)
@@ -223,7 +249,7 @@ namespace WinDurango.UI.Utils
status.Hide();
Logger.WriteError($"{package.DisplayName} failed to uninstall");
Logger.WriteException(ex);
await new NoticeDialog($"{package.DisplayName} failed to uninstall: {ex.Message}", "Error!").Show();
await new NoticeDialog(GetLocalizedText("PackageUninstallFailedEx", package.DisplayName, e.Message), "Error!").Show();
}
return;
}

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic;
using Microsoft.Windows.ApplicationModel.DynamicDependency;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
@@ -8,8 +9,55 @@ namespace WinDurango.UI.Utils
{
public class XHandler
{
public static List<Package> getXPackages(List<Package> packages)
// 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<Package> GetXPackages(List<Package> packages)
{
// first try implementation and it worked hell yeah
List<Package> result = new();
foreach (Package package in packages)
{

View File

@@ -34,6 +34,7 @@
<None Remove="Controls\ContributorInfo.xaml" />
<None Remove="Controls\NewFile1.txt" />
<None Remove="Dialogs\AppListDialog.xaml" />
<None Remove="Dialogs\InstallConfirmationDialog.xaml" />
<None Remove="Pages\AboutPage.xaml" />
<None Remove="Pages\AppsListPage.xaml" />
<None Remove="Pages\SettingsPage.xaml" />
@@ -52,6 +53,7 @@
<PackageReference Include="System.DirectoryServices" Version="8.0.0" />
<PackageReference Include="System.DirectoryServices.AccountManagement" Version="8.0.0" />
<PackageReference Include="System.Drawing.Common" Version="8.0.8" />
<PackageReference Include="WinUI3Localizer" Version="2.2.0" />
<Manifest Include="$(ApplicationManifest)" />
</ItemGroup>
@@ -92,10 +94,26 @@
<EditorConfigFiles Remove="D:\Projects\Dev\C#\WinDurango.UI\.editorconfig" />
</ItemGroup>
<ItemGroup>
<Content Include="Strings\**\*.resw">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
<ItemGroup>
<Content Remove="Strings\en-US\Errors.resw" />
</ItemGroup>
<ItemGroup>
<None Include="D:\Projects\Dev\C#\WinDurango.UI\.editorconfig" />
</ItemGroup>
<ItemGroup>
<Page Update="Dialogs\InstallConfirmationDialog.xaml">
<Generator>MSBuild:Compile</Generator>
</Page>
</ItemGroup>
<ItemGroup>
<Page Update="Dialogs\AppListDialog.xaml">
<Generator>MSBuild:Compile</Generator>