Skip to content

Commit

Permalink
Add update checker which runs on startup
Browse files Browse the repository at this point in the history
  • Loading branch information
ElektroKill committed Sep 17, 2023
1 parent 2defb01 commit 4eeea76
Show file tree
Hide file tree
Showing 8 changed files with 441 additions and 206 deletions.
22 changes: 14 additions & 8 deletions dnSpy/dnSpy/MainApp/AboutScreen.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,15 @@ sealed class AboutScreenDocumentTabContentFactory : IDocumentTabContentFactory {
readonly IDocumentViewerContentFactoryProvider documentViewerContentFactoryProvider;
readonly IAppWindow appWindow;
readonly IExtensionService extensionService;
readonly IUpdateService updateService;
readonly IContentType aboutContentType;

[ImportingConstructor]
AboutScreenDocumentTabContentFactory(IDocumentViewerContentFactoryProvider documentViewerContentFactoryProvider, IAppWindow appWindow, IExtensionService extensionService, IContentTypeRegistryService contentTypeRegistryService) {
AboutScreenDocumentTabContentFactory(IDocumentViewerContentFactoryProvider documentViewerContentFactoryProvider, IAppWindow appWindow, IExtensionService extensionService, IUpdateService updateService, IContentTypeRegistryService contentTypeRegistryService) {
this.documentViewerContentFactoryProvider = documentViewerContentFactoryProvider;
this.appWindow = appWindow;
this.extensionService = extensionService;
this.updateService = updateService;
aboutContentType = contentTypeRegistryService.GetContentType(ContentTypes.AboutDnSpy);
}

Expand All @@ -62,7 +64,7 @@ sealed class AboutScreenDocumentTabContentFactory : IDocumentTabContentFactory {

public DocumentTabContent? Deserialize(Guid guid, ISettingsSection section, IDocumentTabContentFactoryContext context) {
if (guid == GUID_SerializedContent)
return new AboutScreenDocumentTabContent(documentViewerContentFactoryProvider, appWindow, extensionService, aboutContentType);
return new AboutScreenDocumentTabContent(documentViewerContentFactoryProvider, appWindow, extensionService, updateService, aboutContentType);
return null;
}

Expand All @@ -79,20 +81,22 @@ sealed class AboutScreenMenuItem : MenuItemBase {
readonly IDocumentTabService documentTabService;
readonly IAppWindow appWindow;
readonly IExtensionService extensionService;
readonly IUpdateService updateService;
readonly IContentType aboutContentType;

[ImportingConstructor]
AboutScreenMenuItem(IDocumentViewerContentFactoryProvider documentViewerContentFactoryProvider, IDocumentTabService documentTabService, IAppWindow appWindow, IExtensionService extensionService, IContentTypeRegistryService contentTypeRegistryService) {
AboutScreenMenuItem(IDocumentViewerContentFactoryProvider documentViewerContentFactoryProvider, IDocumentTabService documentTabService, IAppWindow appWindow, IExtensionService extensionService, IUpdateService updateService, IContentTypeRegistryService contentTypeRegistryService) {
this.documentViewerContentFactoryProvider = documentViewerContentFactoryProvider;
this.documentTabService = documentTabService;
this.appWindow = appWindow;
this.extensionService = extensionService;
this.updateService = updateService;
aboutContentType = contentTypeRegistryService.GetContentType(ContentTypes.AboutDnSpy);
}

public override void Execute(IMenuItemContext context) {
var tab = documentTabService.GetOrCreateActiveTab();
tab.Show(new AboutScreenDocumentTabContent(documentViewerContentFactoryProvider, appWindow, extensionService, aboutContentType), null, null);
tab.Show(new AboutScreenDocumentTabContent(documentViewerContentFactoryProvider, appWindow, extensionService, updateService, aboutContentType), null, null);
documentTabService.SetFocus(tab);
}
}
Expand All @@ -102,17 +106,19 @@ sealed class AboutScreenDocumentTabContent : DocumentTabContent {

readonly IAppWindow appWindow;
readonly IExtensionService extensionService;
readonly IUpdateService updateService;
readonly IContentType aboutContentType;
readonly IDocumentViewerContentFactoryProvider documentViewerContentFactoryProvider;

public AboutScreenDocumentTabContent(IDocumentViewerContentFactoryProvider documentViewerContentFactoryProvider, IAppWindow appWindow, IExtensionService extensionService, IContentType aboutContentType) {
public AboutScreenDocumentTabContent(IDocumentViewerContentFactoryProvider documentViewerContentFactoryProvider, IAppWindow appWindow, IExtensionService extensionService, IUpdateService updateService, IContentType aboutContentType) {
this.documentViewerContentFactoryProvider = documentViewerContentFactoryProvider;
this.appWindow = appWindow;
this.extensionService = extensionService;
this.updateService = updateService;
this.aboutContentType = aboutContentType;
}

public override DocumentTabContent Clone() => new AboutScreenDocumentTabContent(documentViewerContentFactoryProvider, appWindow, extensionService, aboutContentType);
public override DocumentTabContent Clone() => new AboutScreenDocumentTabContent(documentViewerContentFactoryProvider, appWindow, extensionService, updateService, aboutContentType);
public override DocumentTabUIContext CreateUIContext(IDocumentTabUIContextLocator locator) => (DocumentTabUIContext)locator.Get<IDocumentViewer>();

public override void OnShow(IShowContext ctx) {
Expand Down Expand Up @@ -224,14 +230,14 @@ void Write(IDocumentViewerOutput output) {
WriteResourceFile(output, "dnSpy.LicenseInfo.CREDITS.txt");
}

static async void OnUpdateButtonClick(object sender, RoutedEventArgs e) {
async void OnUpdateButtonClick(object sender, RoutedEventArgs e) {
e.Handled = true;
var button = (Button)sender;

button.IsEnabled = false;
button.Content = dnSpy_Resources.AboutScreen_CheckingForUpdates;

var updateResult = await UpdateChecker.CheckForUpdatesAsync();
var updateResult = await updateService.CheckForUpdatesAsync();
if (!updateResult.Success)
MsgBox.Instance.Show(dnSpy_Resources.AboutScreen_FailedToRetrieveUpdateInfo);
else if (!updateResult.UpdateAvailable)
Expand Down
24 changes: 21 additions & 3 deletions dnSpy/dnSpy/MainApp/Settings/GeneralAppSettingsPage.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,22 @@ sealed class GeneralAppSettingsPageProvider : IAppSettingsPageProvider {
readonly IDsDocumentServiceSettings documentServiceSettings;
readonly AppSettingsImpl appSettings;
readonly MessageBoxService messageBoxService;
readonly IUpdateService updateService;

[ImportingConstructor]
GeneralAppSettingsPageProvider(IThemeServiceImpl themeService, IWindowsExplorerIntegrationService windowsExplorerIntegrationService, IDocumentTabServiceSettings documentTabServiceSettings, DocumentTreeViewSettingsImpl documentTreeViewSettings, IDsDocumentServiceSettings documentServiceSettings, AppSettingsImpl appSettings, MessageBoxService messageBoxService) {
GeneralAppSettingsPageProvider(IThemeServiceImpl themeService, IWindowsExplorerIntegrationService windowsExplorerIntegrationService, IDocumentTabServiceSettings documentTabServiceSettings, DocumentTreeViewSettingsImpl documentTreeViewSettings, IDsDocumentServiceSettings documentServiceSettings, AppSettingsImpl appSettings, MessageBoxService messageBoxService, IUpdateService updateService) {
this.themeService = themeService;
this.windowsExplorerIntegrationService = windowsExplorerIntegrationService;
this.documentTabServiceSettings = documentTabServiceSettings;
this.documentTreeViewSettings = documentTreeViewSettings;
this.documentServiceSettings = documentServiceSettings;
this.appSettings = appSettings;
this.messageBoxService = messageBoxService;
this.updateService = updateService;
}

public IEnumerable<AppSettingsPage> Create() {
yield return new GeneralAppSettingsPage(themeService, windowsExplorerIntegrationService, documentTabServiceSettings, documentTreeViewSettings, documentServiceSettings, appSettings, messageBoxService);
yield return new GeneralAppSettingsPage(themeService, windowsExplorerIntegrationService, documentTabServiceSettings, documentTreeViewSettings, documentServiceSettings, appSettings, messageBoxService, updateService);
}
}

Expand All @@ -74,8 +76,10 @@ sealed class GeneralAppSettingsPage : AppSettingsPage, IAppSettingsPage2 {
readonly IDsDocumentServiceSettings documentServiceSettings;
readonly AppSettingsImpl appSettings;
readonly MessageBoxService messageBoxService;
readonly IUpdateService updateService;

public ICommand ClearAllWarningsCommand => new RelayCommand(a => messageBoxService.EnableAllWarnings(), a => messageBoxService.CanEnableAllWarnings);
public ICommand ResetIgnoredUpdatesCommand => new RelayCommand(a => updateService.ResetIgnoredUpdates(), a => updateService.CanResetIgnoredUpdates);

public ObservableCollection<ThemeVM> ThemesVM { get; }

Expand Down Expand Up @@ -156,14 +160,26 @@ public bool UseMemoryMappedIO {
}
bool useMemoryMappedIO;

public GeneralAppSettingsPage(IThemeServiceImpl themeService, IWindowsExplorerIntegrationService windowsExplorerIntegrationService, IDocumentTabServiceSettings documentTabServiceSettings, DocumentTreeViewSettingsImpl documentTreeViewSettings, IDsDocumentServiceSettings documentServiceSettings, AppSettingsImpl appSettings, MessageBoxService messageBoxService) {
public bool CheckForUpdateOnStartup {
get => checkForUpdateOnStartup;
set {
if (checkForUpdateOnStartup != value) {
checkForUpdateOnStartup = value;
OnPropertyChanged(nameof(CheckForUpdateOnStartup));
}
}
}
bool checkForUpdateOnStartup;

public GeneralAppSettingsPage(IThemeServiceImpl themeService, IWindowsExplorerIntegrationService windowsExplorerIntegrationService, IDocumentTabServiceSettings documentTabServiceSettings, DocumentTreeViewSettingsImpl documentTreeViewSettings, IDsDocumentServiceSettings documentServiceSettings, AppSettingsImpl appSettings, MessageBoxService messageBoxService, IUpdateService updateService) {
this.themeService = themeService ?? throw new ArgumentNullException(nameof(themeService));
this.windowsExplorerIntegrationService = windowsExplorerIntegrationService ?? throw new ArgumentNullException(nameof(windowsExplorerIntegrationService));
this.documentTabServiceSettings = documentTabServiceSettings ?? throw new ArgumentNullException(nameof(documentTabServiceSettings));
this.documentTreeViewSettings = documentTreeViewSettings ?? throw new ArgumentNullException(nameof(documentTreeViewSettings));
this.documentServiceSettings = documentServiceSettings ?? throw new ArgumentNullException(nameof(documentServiceSettings));
this.appSettings = appSettings ?? throw new ArgumentNullException(nameof(appSettings));
this.messageBoxService = messageBoxService ?? throw new ArgumentNullException(nameof(messageBoxService));
this.updateService = updateService ?? throw new ArgumentNullException(nameof(updateService));

ThemesVM = new ObservableCollection<ThemeVM>(themeService.VisibleThemes.Select(a => new ThemeVM(a)));
if (!ThemesVM.Any(a => a.Theme == themeService.Theme))
Expand All @@ -177,6 +193,7 @@ public GeneralAppSettingsPage(IThemeServiceImpl themeService, IWindowsExplorerIn
RestoreTabs = documentTabServiceSettings.RestoreTabs;
DeserializeResources = documentTreeViewSettings.DeserializeResources;
UseMemoryMappedIO = documentServiceSettings.UseMemoryMappedIO;
CheckForUpdateOnStartup = updateService.CheckForUpdatesOnStartup;
}

public override string[]? GetSearchStrings() => ThemesVM.Select(a => a.Name).ToArray();
Expand All @@ -197,6 +214,7 @@ public void OnApply(IAppRefreshSettings appRefreshSettings) {
appRefreshSettings.Add(AppSettingsConstants.DISABLE_MEMORY_MAPPED_IO);
}

updateService.CheckForUpdatesOnStartup = CheckForUpdateOnStartup;
}
}

Expand Down
75 changes: 75 additions & 0 deletions dnSpy/dnSpy/MainApp/StartupUpdateCheck.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*
Copyright (C) 2023 ElektroKill
This file is part of dnSpy
dnSpy is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
dnSpy is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with dnSpy. If not, see <http://www.gnu.org/licenses/>.
*/

using System.ComponentModel.Composition;
using System.Threading.Tasks;
using dnSpy.Contracts.App;
using dnSpy.Contracts.Extension;
using dnSpy.Properties;
using dnSpy.UI;

namespace dnSpy.MainApp {
[ExportAutoLoaded]
sealed class StartupUpdateCheck : IAutoLoaded {
readonly IUpdateService updateService;
readonly IMessageBoxService messageBoxService;
readonly UIDispatcher uiDispatcher;
readonly IAppWindow appWindow;

[ImportingConstructor]
public StartupUpdateCheck(IUpdateService updateService, IMessageBoxService messageBoxService, IAppWindow appWindow, UIDispatcher uiDispatcher) {
this.updateService = updateService;
this.messageBoxService = messageBoxService;
this.uiDispatcher = uiDispatcher;
this.appWindow = appWindow;

if (updateService.CheckForUpdatesOnStartup)
Task.Run(CheckForUpdate);
}

async void CheckForUpdate() {
var updateInfo = await updateService.CheckForUpdatesAsync();

if (!updateInfo.Success)
return;
if (!updateInfo.UpdateAvailable || updateService.IsUpdateIgnored(updateInfo.VersionInfo))
return;

string message = string.Format(dnSpy_Resources.InfoBar_NewUpdateAvailable, updateInfo.VersionInfo.Version);
DisplayNotification(message, InfoBarIcon.Information, new[] {
new InfoBarInteraction(dnSpy_Resources.InfoBar_OpenDownloadPage, ctx => {
AboutHelpers.OpenWebPage(updateInfo.VersionInfo.DownloadUrl, messageBoxService);
ctx.CloseElement();
}),
new InfoBarInteraction(dnSpy_Resources.InfoBar_IgnoreThisUpdate, ctx => {
updateService.MarkUpdateAsIgnored(updateInfo.VersionInfo);
ctx.CloseElement();
})
});
}

void DisplayNotification(string message, InfoBarIcon icon, InfoBarInteraction[] interactions) {
if (uiDispatcher.CheckAccess()) {
appWindow.InfoBar.Show(message, icon, interactions);
return;
}
uiDispatcher.UIBackground(() => appWindow.InfoBar.Show(message, icon, interactions));
}
}
}
100 changes: 0 additions & 100 deletions dnSpy/dnSpy/MainApp/UpdateChecker.cs

This file was deleted.

Loading

0 comments on commit 4eeea76

Please sign in to comment.