From bf8065e6eb03debe8e422f7709698470b44aa642 Mon Sep 17 00:00:00 2001 From: Christoph Wille Date: Sun, 4 Jun 2023 13:31:59 +0200 Subject: [PATCH 1/7] Move UpdateSettings and AvailableVersionInfo to namespace level --- ILSpy/AboutPage.cs | 137 +++++++++++++++++++++++---------------------- 1 file changed, 69 insertions(+), 68 deletions(-) diff --git a/ILSpy/AboutPage.cs b/ILSpy/AboutPage.cs index 0ac9866bf2..2a8b86659d 100644 --- a/ILSpy/AboutPage.cs +++ b/ILSpy/AboutPage.cs @@ -218,74 +218,6 @@ static async Task GetLatestVersionAsync() return latestAvailableVersion; } - sealed class AvailableVersionInfo - { - public Version Version; - public string DownloadUrl; - } - - sealed class UpdateSettings : INotifyPropertyChanged - { - public UpdateSettings(ILSpySettings spySettings) - { - XElement s = spySettings["UpdateSettings"]; - this.automaticUpdateCheckEnabled = (bool?)s.Element("AutomaticUpdateCheckEnabled") ?? true; - try - { - this.lastSuccessfulUpdateCheck = (DateTime?)s.Element("LastSuccessfulUpdateCheck"); - } - catch (FormatException) - { - // avoid crashing on settings files invalid due to - // https://github.com/icsharpcode/ILSpy/issues/closed/#issue/2 - } - } - - bool automaticUpdateCheckEnabled; - - public bool AutomaticUpdateCheckEnabled { - get { return automaticUpdateCheckEnabled; } - set { - if (automaticUpdateCheckEnabled != value) - { - automaticUpdateCheckEnabled = value; - Save(); - OnPropertyChanged(nameof(AutomaticUpdateCheckEnabled)); - } - } - } - - DateTime? lastSuccessfulUpdateCheck; - - public DateTime? LastSuccessfulUpdateCheck { - get { return lastSuccessfulUpdateCheck; } - set { - if (lastSuccessfulUpdateCheck != value) - { - lastSuccessfulUpdateCheck = value; - Save(); - OnPropertyChanged(nameof(LastSuccessfulUpdateCheck)); - } - } - } - - public void Save() - { - XElement updateSettings = new XElement("UpdateSettings"); - updateSettings.Add(new XElement("AutomaticUpdateCheckEnabled", automaticUpdateCheckEnabled)); - if (lastSuccessfulUpdateCheck != null) - updateSettings.Add(new XElement("LastSuccessfulUpdateCheck", lastSuccessfulUpdateCheck)); - ILSpySettings.SaveSettings(updateSettings); - } - - public event PropertyChangedEventHandler PropertyChanged; - - void OnPropertyChanged(string propertyName) - { - PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); - } - } - /// /// If automatic update checking is enabled, checks if there are any updates available. /// Returns the download URL if an update is available. @@ -349,4 +281,73 @@ public interface IAboutPageAddition { void Write(ISmartTextOutput textOutput); } + + sealed class AvailableVersionInfo + { + public Version Version; + public string DownloadUrl; + } + + sealed class UpdateSettings : INotifyPropertyChanged + { + public UpdateSettings(ILSpySettings spySettings) + { + XElement s = spySettings["UpdateSettings"]; + this.automaticUpdateCheckEnabled = (bool?)s.Element("AutomaticUpdateCheckEnabled") ?? true; + try + { + this.lastSuccessfulUpdateCheck = (DateTime?)s.Element("LastSuccessfulUpdateCheck"); + } + catch (FormatException) + { + // avoid crashing on settings files invalid due to + // https://github.com/icsharpcode/ILSpy/issues/closed/#issue/2 + } + } + + bool automaticUpdateCheckEnabled; + + public bool AutomaticUpdateCheckEnabled { + get { return automaticUpdateCheckEnabled; } + set { + if (automaticUpdateCheckEnabled != value) + { + automaticUpdateCheckEnabled = value; + Save(); + OnPropertyChanged(nameof(AutomaticUpdateCheckEnabled)); + } + } + } + + DateTime? lastSuccessfulUpdateCheck; + + public DateTime? LastSuccessfulUpdateCheck { + get { return lastSuccessfulUpdateCheck; } + set { + if (lastSuccessfulUpdateCheck != value) + { + lastSuccessfulUpdateCheck = value; + Save(); + OnPropertyChanged(nameof(LastSuccessfulUpdateCheck)); + } + } + } + + public void Save() + { + XElement updateSettings = new XElement("UpdateSettings"); + updateSettings.Add(new XElement("AutomaticUpdateCheckEnabled", automaticUpdateCheckEnabled)); + if (lastSuccessfulUpdateCheck != null) + updateSettings.Add(new XElement("LastSuccessfulUpdateCheck", lastSuccessfulUpdateCheck)); + ILSpySettings.SaveSettings(updateSettings); + } + + public event PropertyChangedEventHandler PropertyChanged; + + void OnPropertyChanged(string propertyName) + { + PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } + } From 22147ce6bc3cc45ef3871f6b4c7fdef13303160f Mon Sep 17 00:00:00 2001 From: Christoph Wille Date: Sun, 4 Jun 2023 13:47:14 +0200 Subject: [PATCH 2/7] Basic WPF Sparkle setup (note JsonConfiguration is not yet active, issue opened) --- ILSpy/ILSpy.csproj | 1 + ILSpy/MainWindow.xaml.cs | 41 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index d33163bad0..95a2d755ef 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -45,6 +45,7 @@ + diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index eaa65475ba..f474d4093e 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -57,6 +57,11 @@ using Microsoft.Win32; +using NetSparkleUpdater.Enums; +using NetSparkleUpdater.SignatureVerifiers; +using NetSparkleUpdater; +using System.Runtime.InteropServices; + namespace ICSharpCode.ILSpy { /// @@ -72,6 +77,8 @@ partial class MainWindow : Window AssemblyList assemblyList; AssemblyListTreeNode assemblyListTreeNode; + SparkleUpdater _sparkle; + static MainWindow instance; public static MainWindow Instance { @@ -895,6 +902,37 @@ void MainWindow_Loaded(object sender, RoutedEventArgs e) } Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() => OpenAssemblies(spySettings))); + + + var s = new UpdateSettings(spySettings); + bool automaticCheckingEnabled = s.AutomaticUpdateCheckEnabled; +#if DEBUG + // automaticCheckingEnabled = false; +#endif + + if (automaticCheckingEnabled) + EnableSparkleUpdateChecking(); + } + + void EnableSparkleUpdateChecking() + { + // We'd need two appcast.xml's, one for x64 and one for arm64 + if (RuntimeInformation.ProcessArchitecture != Architecture.X64) + return; + + // https://github.com/NetSparkleUpdater/NetSparkle/blob/develop/src/NetSparkle.Samples.NetCore.WPF/MainWindow.xaml.cs + string sparkleSettingsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ICSharpCode\\ILSpy-sparkle.json"); + + _sparkle = new SparkleUpdater( + "https://ilspy.net/appcast.xml", + new Ed25519Checker(SecurityMode.Strict, "s2P6MPexSRSjod77aWUjgVKj/gKYYAeqgHY/0Gf8b78=") + ) { + UIFactory = new NetSparkleUpdater.UI.WPF.UIFactory(null), + RelaunchAfterUpdate = false, + CustomInstallerArguments = "", + // Configuration = new JSONConfiguration(null, sparkleSettingsPath) + }; + _sparkle.StartLoop(true); } void OpenAssemblies(ILSpySettings spySettings) @@ -951,6 +989,9 @@ internal static bool FormatExceptions(App.ExceptionData[] exceptions, StringBuil public async Task ShowMessageIfUpdatesAvailableAsync(ILSpySettings spySettings, bool forceCheck = false) { + // TODO: Properly replace old code-paths, this is for UI testing of Netsparkle only + var info = await _sparkle.CheckForUpdatesAtUserRequest(); + string downloadUrl; if (forceCheck) { From 14944e166b2c23772336627d733fb2a251023db4 Mon Sep 17 00:00:00 2001 From: Christoph Wille Date: Mon, 5 Jun 2023 06:39:19 +0200 Subject: [PATCH 3/7] Enable JSONConfiguration with latest test package, make notes on update variations --- ILSpy/ILSpy.csproj | 2 +- ILSpy/MainWindow.xaml.cs | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 95a2d755ef..f89e908b5d 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -45,7 +45,7 @@ - + diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index f474d4093e..4946e580fc 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -25,6 +25,7 @@ using System.Linq; using System.Reflection.Metadata; using System.Reflection.Metadata.Ecma335; +using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using System.Windows; @@ -57,10 +58,10 @@ using Microsoft.Win32; +using NetSparkleUpdater; +using NetSparkleUpdater.Configurations; using NetSparkleUpdater.Enums; using NetSparkleUpdater.SignatureVerifiers; -using NetSparkleUpdater; -using System.Runtime.InteropServices; namespace ICSharpCode.ILSpy { @@ -906,9 +907,15 @@ void MainWindow_Loaded(object sender, RoutedEventArgs e) var s = new UpdateSettings(spySettings); bool automaticCheckingEnabled = s.AutomaticUpdateCheckEnabled; + + // TODO: That would need to be way more sophisticated - we ship zip, msi, vsix (actually doing an update-check there is wrong even today) + // Multiple of those could be installed on the same machine in multiple versions (esp. zip) + // Somehow we'd need to "tag" the version running from our msi installer, and only then offering auto-update + #if DEBUG // automaticCheckingEnabled = false; #endif + // TODO: Additional check if branch version if (automaticCheckingEnabled) EnableSparkleUpdateChecking(); @@ -930,7 +937,7 @@ void EnableSparkleUpdateChecking() UIFactory = new NetSparkleUpdater.UI.WPF.UIFactory(null), RelaunchAfterUpdate = false, CustomInstallerArguments = "", - // Configuration = new JSONConfiguration(null, sparkleSettingsPath) + Configuration = new JSONConfiguration(null, sparkleSettingsPath) }; _sparkle.StartLoop(true); } From 22d98f5857afc4e4ed2634180d779113e2d8bc15 Mon Sep 17 00:00:00 2001 From: Christoph Wille Date: Mon, 5 Jun 2023 17:17:56 +0200 Subject: [PATCH 4/7] Properly use accessor in JSONConfiguration --- ILSpy/ILSpy.csproj | 2 +- ILSpy/MainWindow.xaml.cs | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index f89e908b5d..aa34cc46c3 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -45,7 +45,7 @@ - + diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index 4946e580fc..f0303ea0c2 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -930,15 +930,18 @@ void EnableSparkleUpdateChecking() // https://github.com/NetSparkleUpdater/NetSparkle/blob/develop/src/NetSparkle.Samples.NetCore.WPF/MainWindow.xaml.cs string sparkleSettingsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ICSharpCode\\ILSpy-sparkle.json"); + // var icsdasm = typeof(DecompilerVersionInfo).Assembly.FullName; + _sparkle = new SparkleUpdater( "https://ilspy.net/appcast.xml", new Ed25519Checker(SecurityMode.Strict, "s2P6MPexSRSjod77aWUjgVKj/gKYYAeqgHY/0Gf8b78=") ) { - UIFactory = new NetSparkleUpdater.UI.WPF.UIFactory(null), + UIFactory = new NetSparkleUpdater.UI.WPF.UIFactory(Images.ILSpyIcon), RelaunchAfterUpdate = false, CustomInstallerArguments = "", - Configuration = new JSONConfiguration(null, sparkleSettingsPath) + Configuration = new JSONConfiguration(new NetSparkleUpdater.AssemblyAccessors.AssemblyReflectionAccessor(null), sparkleSettingsPath) }; + _sparkle.StartLoop(true); } From 9cfba701d00dd3518abf18367aabb66e264cbee7 Mon Sep 17 00:00:00 2001 From: Christoph Wille Date: Tue, 6 Jun 2023 15:05:28 +0200 Subject: [PATCH 5/7] Base sample for dark background and HTML customization - overriding UIFactory would be the way to go though re: changing of themes and not defaulting to one style on startup https://github.com/NetSparkleUpdater/NetSparkle/issues/467 --- ILSpy/ILSpy.csproj | 2 +- ILSpy/MainWindow.xaml.cs | 24 ++++++++++++++++++++---- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index aa34cc46c3..c6c805626e 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -45,7 +45,7 @@ - + diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index f0303ea0c2..3e49b8a9fd 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -62,6 +62,7 @@ using NetSparkleUpdater.Configurations; using NetSparkleUpdater.Enums; using NetSparkleUpdater.SignatureVerifiers; +using NetSparkleUpdater.UI.WPF; namespace ICSharpCode.ILSpy { @@ -910,7 +911,8 @@ void MainWindow_Loaded(object sender, RoutedEventArgs e) // TODO: That would need to be way more sophisticated - we ship zip, msi, vsix (actually doing an update-check there is wrong even today) // Multiple of those could be installed on the same machine in multiple versions (esp. zip) - // Somehow we'd need to "tag" the version running from our msi installer, and only then offering auto-update + // Somehow we'd need to "tag" the version running from our msi installer, and only then offering auto-update (eg MsiInstaller.txt marker file) + // And then have an IUpdateService with one impl existing plus one for auto-updating #if DEBUG // automaticCheckingEnabled = false; @@ -927,16 +929,30 @@ void EnableSparkleUpdateChecking() if (RuntimeInformation.ProcessArchitecture != Architecture.X64) return; + bool isLightTheme = ThemeManager.Current.Theme.Contains("light", StringComparison.InvariantCultureIgnoreCase); + + var extraHeadAdditionForReleaseNotes = ""; + // https://github.com/NetSparkleUpdater/NetSparkle/blob/develop/src/NetSparkle.Samples.NetCore.WPF/MainWindow.xaml.cs string sparkleSettingsPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ICSharpCode\\ILSpy-sparkle.json"); - // var icsdasm = typeof(DecompilerVersionInfo).Assembly.FullName; - _sparkle = new SparkleUpdater( "https://ilspy.net/appcast.xml", new Ed25519Checker(SecurityMode.Strict, "s2P6MPexSRSjod77aWUjgVKj/gKYYAeqgHY/0Gf8b78=") ) { - UIFactory = new NetSparkleUpdater.UI.WPF.UIFactory(Images.ILSpyIcon), + UIFactory = new UIFactory(Images.ILSpyIcon) { + UseStaticUpdateWindowBackgroundColor = false, + AdditionalReleaseNotesHeaderHTML = extraHeadAdditionForReleaseNotes + }, RelaunchAfterUpdate = false, CustomInstallerArguments = "", Configuration = new JSONConfiguration(new NetSparkleUpdater.AssemblyAccessors.AssemblyReflectionAccessor(null), sparkleSettingsPath) From 410e8132c28ae4d9b04a2758cf954962d0298dc0 Mon Sep 17 00:00:00 2001 From: Christoph Wille Date: Wed, 7 Jun 2023 06:59:58 +0200 Subject: [PATCH 6/7] Try styling all windows for Netsparkle --- ILSpy/ILSpy.csproj | 2 +- ILSpy/MainWindow.xaml.cs | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index c6c805626e..33ef1b9eff 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -45,7 +45,7 @@ - + diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index 3e49b8a9fd..c34bf5a476 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -929,6 +929,7 @@ void EnableSparkleUpdateChecking() if (RuntimeInformation.ProcessArchitecture != Architecture.X64) return; + // This should update with UpdateTheme bool isLightTheme = ThemeManager.Current.Theme.Contains("light", StringComparison.InvariantCultureIgnoreCase); var extraHeadAdditionForReleaseNotes = "