mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Implemented Windows updating
This commit is contained in:
parent
667663dadf
commit
67a4672c66
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Shared.Services.MainWindow;
|
namespace Artemis.UI.Shared.Services.MainWindow;
|
||||||
|
|
||||||
@ -12,6 +13,11 @@ public interface IMainWindowService : IArtemisSharedUIService
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
bool IsMainWindowOpen { get; }
|
bool IsMainWindowOpen { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the host screen contained in the main window
|
||||||
|
/// </summary>
|
||||||
|
IScreen? HostScreen { get; set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sets up the main window provider that controls the state of the main window
|
/// Sets up the main window provider that controls the state of the main window
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Shared.Services.MainWindow;
|
namespace Artemis.UI.Shared.Services.MainWindow;
|
||||||
|
|
||||||
@ -6,6 +7,12 @@ internal class MainWindowService : IMainWindowService
|
|||||||
{
|
{
|
||||||
private IMainWindowProvider? _mainWindowManager;
|
private IMainWindowProvider? _mainWindowManager;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool IsMainWindowOpen { get; private set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public IScreen? HostScreen { get; set; }
|
||||||
|
|
||||||
protected virtual void OnMainWindowOpened()
|
protected virtual void OnMainWindowOpened()
|
||||||
{
|
{
|
||||||
MainWindowOpened?.Invoke(this, EventArgs.Empty);
|
MainWindowOpened?.Invoke(this, EventArgs.Empty);
|
||||||
@ -64,8 +71,6 @@ internal class MainWindowService : IMainWindowService
|
|||||||
OnMainWindowUnfocused();
|
OnMainWindowUnfocused();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsMainWindowOpen { get; private set; }
|
|
||||||
|
|
||||||
public void ConfigureMainWindowProvider(IMainWindowProvider mainWindowProvider)
|
public void ConfigureMainWindowProvider(IMainWindowProvider mainWindowProvider)
|
||||||
{
|
{
|
||||||
if (mainWindowProvider == null) throw new ArgumentNullException(nameof(mainWindowProvider));
|
if (mainWindowProvider == null) throw new ArgumentNullException(nameof(mainWindowProvider));
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using Artemis.Core.Providers;
|
using Artemis.Core.Providers;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.UI.Services.Updating;
|
||||||
using Artemis.UI.Shared.Providers;
|
using Artemis.UI.Shared.Providers;
|
||||||
using Artemis.UI.Windows.Providers;
|
using Artemis.UI.Windows.Providers;
|
||||||
using Artemis.UI.Windows.Providers.Input;
|
using Artemis.UI.Windows.Providers.Input;
|
||||||
@ -22,5 +23,6 @@ public static class UIContainerExtensions
|
|||||||
container.Register<IGraphicsContextProvider, GraphicsContextProvider>(Reuse.Singleton);
|
container.Register<IGraphicsContextProvider, GraphicsContextProvider>(Reuse.Singleton);
|
||||||
container.Register<IAutoRunProvider, AutoRunProvider>();
|
container.Register<IAutoRunProvider, AutoRunProvider>();
|
||||||
container.Register<InputProvider, WindowsInputProvider>(serviceKey: WindowsInputProvider.Id);
|
container.Register<InputProvider, WindowsInputProvider>(serviceKey: WindowsInputProvider.Id);
|
||||||
|
container.Register<IUpdateNotificationProvider, WindowsUpdateNotificationProvider>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,146 @@
|
|||||||
|
using System;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Windows.UI.Notifications;
|
||||||
|
using Artemis.UI.Screens.Settings;
|
||||||
|
using Artemis.UI.Services.Updating;
|
||||||
|
using Artemis.UI.Shared.Services.MainWindow;
|
||||||
|
using Avalonia.Threading;
|
||||||
|
using Microsoft.Toolkit.Uwp.Notifications;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Windows.Providers;
|
||||||
|
|
||||||
|
public class WindowsUpdateNotificationProvider : IUpdateNotificationProvider
|
||||||
|
{
|
||||||
|
private readonly Func<string, ReleaseInstaller> _getReleaseInstaller;
|
||||||
|
private readonly Func<IScreen, SettingsViewModel> _getSettingsViewModel;
|
||||||
|
private readonly IMainWindowService _mainWindowService;
|
||||||
|
private readonly IUpdateService _updateService;
|
||||||
|
|
||||||
|
public WindowsUpdateNotificationProvider(IMainWindowService mainWindowService,
|
||||||
|
IUpdateService updateService,
|
||||||
|
Func<IScreen, SettingsViewModel> getSettingsViewModel,
|
||||||
|
Func<string, ReleaseInstaller> getReleaseInstaller)
|
||||||
|
{
|
||||||
|
_mainWindowService = mainWindowService;
|
||||||
|
_updateService = updateService;
|
||||||
|
_getSettingsViewModel = getSettingsViewModel;
|
||||||
|
_getReleaseInstaller = getReleaseInstaller;
|
||||||
|
ToastNotificationManagerCompat.OnActivated += ToastNotificationManagerCompatOnOnActivated;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void ToastNotificationManagerCompatOnOnActivated(ToastNotificationActivatedEventArgsCompat e)
|
||||||
|
{
|
||||||
|
ToastArguments args = ToastArguments.Parse(e.Argument);
|
||||||
|
string releaseId = args.Get("releaseId");
|
||||||
|
string releaseVersion = args.Get("releaseVersion");
|
||||||
|
string action = "view-changes";
|
||||||
|
if (args.Contains("action"))
|
||||||
|
action = args.Get("action");
|
||||||
|
|
||||||
|
if (action == "install")
|
||||||
|
await InstallRelease(releaseId, releaseVersion);
|
||||||
|
else if (action == "view-changes")
|
||||||
|
ViewRelease(releaseId);
|
||||||
|
else if (action == "restart-for-update")
|
||||||
|
_updateService.RestartForUpdate(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task ShowNotification(string releaseId, string releaseVersion)
|
||||||
|
{
|
||||||
|
new ToastContentBuilder()
|
||||||
|
.AddArgument("releaseId", releaseId)
|
||||||
|
.AddArgument("releaseVersion", releaseVersion)
|
||||||
|
.AddText("Update available")
|
||||||
|
.AddText($"Artemis version {releaseVersion} has been released")
|
||||||
|
.AddButton(new ToastButton()
|
||||||
|
.SetContent("Install")
|
||||||
|
.AddArgument("action", "install").SetAfterActivationBehavior(ToastAfterActivationBehavior.PendingUpdate))
|
||||||
|
.AddButton(new ToastButton().SetContent("View changes").AddArgument("action", "view-changes"))
|
||||||
|
.Show(t => t.Tag = releaseId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ViewRelease(string releaseId)
|
||||||
|
{
|
||||||
|
Dispatcher.UIThread.Post(() =>
|
||||||
|
{
|
||||||
|
_mainWindowService.OpenMainWindow();
|
||||||
|
|
||||||
|
// TODO: When proper routing has been implemented, use that here
|
||||||
|
// Create a settings VM to navigate to
|
||||||
|
SettingsViewModel settingsViewModel = _getSettingsViewModel(_mainWindowService.HostScreen);
|
||||||
|
// Get the release tab
|
||||||
|
ReleasesTabViewModel releaseTabViewModel = (ReleasesTabViewModel) settingsViewModel.SettingTabs.First(t => t is ReleasesTabViewModel);
|
||||||
|
|
||||||
|
// Navigate to the settings VM
|
||||||
|
_mainWindowService.HostScreen.Router.Navigate.Execute(settingsViewModel);
|
||||||
|
// Navigate to the release tab
|
||||||
|
releaseTabViewModel.PreselectId = releaseId;
|
||||||
|
settingsViewModel.SelectedTab = releaseTabViewModel;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task InstallRelease(string releaseId, string releaseVersion)
|
||||||
|
{
|
||||||
|
ReleaseInstaller installer = _getReleaseInstaller(releaseId);
|
||||||
|
void InstallerOnPropertyChanged(object? sender, PropertyChangedEventArgs e) => UpdateInstallProgress(releaseId, installer);
|
||||||
|
|
||||||
|
new ToastContentBuilder()
|
||||||
|
.AddArgument("releaseId", releaseId)
|
||||||
|
.AddArgument("releaseVersion", releaseVersion)
|
||||||
|
.AddAudio(new ToastAudio {Silent = true})
|
||||||
|
.AddText("Installing Artemis update")
|
||||||
|
.AddVisualChild(new AdaptiveProgressBar()
|
||||||
|
{
|
||||||
|
Title = releaseVersion,
|
||||||
|
Value = new BindableProgressBarValue("progressValue"),
|
||||||
|
Status = new BindableString("progressStatus")
|
||||||
|
})
|
||||||
|
.AddButton(new ToastButton().SetContent("Cancel").AddArgument("action", "cancel"))
|
||||||
|
.Show(t =>
|
||||||
|
{
|
||||||
|
t.Tag = releaseId;
|
||||||
|
t.Data = GetInstallerNotificationData(installer);
|
||||||
|
});
|
||||||
|
|
||||||
|
await Task.Delay(2000);
|
||||||
|
installer.PropertyChanged += InstallerOnPropertyChanged;
|
||||||
|
await installer.InstallAsync(CancellationToken.None);
|
||||||
|
installer.PropertyChanged -= InstallerOnPropertyChanged;
|
||||||
|
|
||||||
|
_updateService.QueueUpdate();
|
||||||
|
|
||||||
|
new ToastContentBuilder()
|
||||||
|
.AddArgument("releaseId", releaseId)
|
||||||
|
.AddArgument("releaseVersion", releaseVersion)
|
||||||
|
.AddAudio(new ToastAudio {Silent = true})
|
||||||
|
.AddText("Update ready")
|
||||||
|
.AddText($"Artemis version {releaseVersion} is ready to be applied")
|
||||||
|
.AddButton(new ToastButton().SetContent("Restart Artemis").AddArgument("action", "restart-for-update"))
|
||||||
|
.AddButton(new ToastButton().SetContent("Later").AddArgument("action", "postpone-update"))
|
||||||
|
.Show(t => t.Tag = releaseId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateInstallProgress(string releaseId, ReleaseInstaller installer)
|
||||||
|
{
|
||||||
|
ToastNotificationManagerCompat.CreateToastNotifier().Update(GetInstallerNotificationData(installer), releaseId);
|
||||||
|
}
|
||||||
|
|
||||||
|
private NotificationData GetInstallerNotificationData(ReleaseInstaller installer)
|
||||||
|
{
|
||||||
|
NotificationData data = new()
|
||||||
|
{
|
||||||
|
Values =
|
||||||
|
{
|
||||||
|
["progressValue"] = (installer.Progress / 100f).ToString(CultureInfo.InvariantCulture),
|
||||||
|
["progressStatus"] = installer.Status
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -36,7 +36,7 @@ public static class UIContainerExtensions
|
|||||||
|
|
||||||
container.Register<NodeScriptWindowViewModelBase, NodeScriptWindowViewModel>(Reuse.Singleton);
|
container.Register<NodeScriptWindowViewModelBase, NodeScriptWindowViewModel>(Reuse.Singleton);
|
||||||
container.Register<IPropertyVmFactory, PropertyVmFactory>(Reuse.Singleton);
|
container.Register<IPropertyVmFactory, PropertyVmFactory>(Reuse.Singleton);
|
||||||
container.Register<IUpdateNotificationProvider, SimpleUpdateNotificationProvider>();
|
container.Register<IUpdateNotificationProvider, InAppUpdateNotificationProvider>();
|
||||||
|
|
||||||
container.RegisterMany(thisAssembly, type => type.IsAssignableTo<IArtemisUIService>(), Reuse.Singleton);
|
container.RegisterMany(thisAssembly, type => type.IsAssignableTo<IArtemisUIService>(), Reuse.Singleton);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,7 +58,8 @@ public class RootViewModel : ActivatableViewModelBase, IScreen, IMainWindowProvi
|
|||||||
_lifeTime = (IClassicDesktopStyleApplicationLifetime) Application.Current!.ApplicationLifetime!;
|
_lifeTime = (IClassicDesktopStyleApplicationLifetime) Application.Current!.ApplicationLifetime!;
|
||||||
|
|
||||||
mainWindowService.ConfigureMainWindowProvider(this);
|
mainWindowService.ConfigureMainWindowProvider(this);
|
||||||
|
mainWindowService.HostScreen = this;
|
||||||
|
|
||||||
DisplayAccordingToSettings();
|
DisplayAccordingToSettings();
|
||||||
Router.CurrentViewModel.Subscribe(UpdateTitleBarViewModel);
|
Router.CurrentViewModel.Subscribe(UpdateTitleBarViewModel);
|
||||||
Task.Run(() =>
|
Task.Run(() =>
|
||||||
@ -230,11 +231,6 @@ public class RootViewModel : ActivatableViewModelBase, IScreen, IMainWindowProvi
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public void SaveWindowBounds(int x, int y, int width, int height)
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class EmptyViewModel : MainScreenViewModel
|
internal class EmptyViewModel : MainScreenViewModel
|
||||||
|
|||||||
@ -2,10 +2,12 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:settings="clr-namespace:Artemis.UI.Screens.Settings"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.Settings.SettingsView">
|
x:Class="Artemis.UI.Screens.Settings.SettingsView"
|
||||||
|
x:DataType="settings:SettingsViewModel">
|
||||||
<Border Classes="router-container">
|
<Border Classes="router-container">
|
||||||
<TabControl Margin="12" Items="{Binding SettingTabs}">
|
<TabControl Margin="12" Items="{CompiledBinding SettingTabs}" SelectedItem="{CompiledBinding SelectedTab}">
|
||||||
<TabControl.ItemTemplate>
|
<TabControl.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<TextBlock Text="{Binding DisplayName}" />
|
<TextBlock Text="{Binding DisplayName}" />
|
||||||
|
|||||||
@ -6,6 +6,8 @@ namespace Artemis.UI.Screens.Settings;
|
|||||||
|
|
||||||
public class SettingsViewModel : MainScreenViewModel
|
public class SettingsViewModel : MainScreenViewModel
|
||||||
{
|
{
|
||||||
|
private ActivatableViewModelBase _selectedTab;
|
||||||
|
|
||||||
public SettingsViewModel(IScreen hostScreen,
|
public SettingsViewModel(IScreen hostScreen,
|
||||||
GeneralTabViewModel generalTabViewModel,
|
GeneralTabViewModel generalTabViewModel,
|
||||||
PluginsTabViewModel pluginsTabViewModel,
|
PluginsTabViewModel pluginsTabViewModel,
|
||||||
@ -24,4 +26,10 @@ public class SettingsViewModel : MainScreenViewModel
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ObservableCollection<ActivatableViewModelBase> SettingTabs { get; }
|
public ObservableCollection<ActivatableViewModelBase> SettingTabs { get; }
|
||||||
|
|
||||||
|
public ActivatableViewModelBase SelectedTab
|
||||||
|
{
|
||||||
|
get => _selectedTab;
|
||||||
|
set => RaiseAndSetIfChanged(ref _selectedTab, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -51,11 +51,12 @@ public class ReleasesTabViewModel : ActivatableViewModelBase
|
|||||||
{
|
{
|
||||||
await updateService.CacheLatestRelease();
|
await updateService.CacheLatestRelease();
|
||||||
await GetMoreReleases(d.AsCancellationToken());
|
await GetMoreReleases(d.AsCancellationToken());
|
||||||
SelectedReleaseViewModel = ReleaseViewModels.FirstOrDefault();
|
SelectedReleaseViewModel = ReleaseViewModels.FirstOrDefault(r => r.ReleaseId == PreselectId) ?? ReleaseViewModels.FirstOrDefault();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReadOnlyObservableCollection<ReleaseViewModel> ReleaseViewModels { get; }
|
public ReadOnlyObservableCollection<ReleaseViewModel> ReleaseViewModels { get; }
|
||||||
|
public string? PreselectId { get; set; }
|
||||||
|
|
||||||
public ReleaseViewModel? SelectedReleaseViewModel
|
public ReleaseViewModel? SelectedReleaseViewModel
|
||||||
{
|
{
|
||||||
|
|||||||
@ -22,7 +22,7 @@ public class ReleaseViewModel : ActivatableViewModelBase
|
|||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
private readonly ILogger _logger;
|
||||||
private readonly INotificationService _notificationService;
|
private readonly INotificationService _notificationService;
|
||||||
private readonly string _releaseId;
|
private readonly IUpdateService _updateService;
|
||||||
private readonly Platform _updatePlatform;
|
private readonly Platform _updatePlatform;
|
||||||
private readonly IUpdatingClient _updatingClient;
|
private readonly IUpdatingClient _updatingClient;
|
||||||
private readonly IWindowService _windowService;
|
private readonly IWindowService _windowService;
|
||||||
@ -46,10 +46,10 @@ public class ReleaseViewModel : ActivatableViewModelBase
|
|||||||
IUpdateService updateService,
|
IUpdateService updateService,
|
||||||
IWindowService windowService)
|
IWindowService windowService)
|
||||||
{
|
{
|
||||||
_releaseId = releaseId;
|
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_updatingClient = updatingClient;
|
_updatingClient = updatingClient;
|
||||||
_notificationService = notificationService;
|
_notificationService = notificationService;
|
||||||
|
_updateService = updateService;
|
||||||
_windowService = windowService;
|
_windowService = windowService;
|
||||||
|
|
||||||
if (OperatingSystem.IsWindows())
|
if (OperatingSystem.IsWindows())
|
||||||
@ -61,12 +61,13 @@ public class ReleaseViewModel : ActivatableViewModelBase
|
|||||||
else
|
else
|
||||||
throw new PlatformNotSupportedException("Cannot auto update on the current platform");
|
throw new PlatformNotSupportedException("Cannot auto update on the current platform");
|
||||||
|
|
||||||
|
ReleaseId = releaseId;
|
||||||
Version = version;
|
Version = version;
|
||||||
CreatedAt = createdAt;
|
CreatedAt = createdAt;
|
||||||
ReleaseInstaller = updateService.GetReleaseInstaller(_releaseId);
|
ReleaseInstaller = updateService.GetReleaseInstaller(ReleaseId);
|
||||||
|
|
||||||
Install = ReactiveCommand.CreateFromTask(ExecuteInstall);
|
Install = ReactiveCommand.CreateFromTask(ExecuteInstall);
|
||||||
Restart = ReactiveCommand.Create(() => Utilities.ApplyUpdate(false));
|
Restart = ReactiveCommand.Create(ExecuteRestart);
|
||||||
CancelInstall = ReactiveCommand.Create(() => _installerCts?.Cancel());
|
CancelInstall = ReactiveCommand.Create(() => _installerCts?.Cancel());
|
||||||
|
|
||||||
this.WhenActivated(d =>
|
this.WhenActivated(d =>
|
||||||
@ -74,12 +75,19 @@ public class ReleaseViewModel : ActivatableViewModelBase
|
|||||||
// There's no point in running anything but the latest version of the current channel.
|
// There's no point in running anything but the latest version of the current channel.
|
||||||
// Perhaps later that won't be true anymore, then we could consider allowing to install
|
// Perhaps later that won't be true anymore, then we could consider allowing to install
|
||||||
// older versions with compatible database versions.
|
// older versions with compatible database versions.
|
||||||
InstallationAvailable = updateService.CachedLatestRelease?.Id == _releaseId;
|
InstallationAvailable = _updateService.CachedLatestRelease?.Id == ReleaseId;
|
||||||
RetrieveDetails(d.AsCancellationToken()).ToObservable();
|
RetrieveDetails(d.AsCancellationToken()).ToObservable();
|
||||||
Disposable.Create(_installerCts, cts => cts?.Cancel()).DisposeWith(d);
|
Disposable.Create(_installerCts, cts => cts?.Cancel()).DisposeWith(d);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public string ReleaseId { get; }
|
||||||
|
|
||||||
|
private void ExecuteRestart()
|
||||||
|
{
|
||||||
|
_updateService.RestartForUpdate(false);
|
||||||
|
}
|
||||||
|
|
||||||
public ReactiveCommand<Unit, Unit> Restart { get; set; }
|
public ReactiveCommand<Unit, Unit> Restart { get; set; }
|
||||||
public ReactiveCommand<Unit, Unit> Install { get; }
|
public ReactiveCommand<Unit, Unit> Install { get; }
|
||||||
public ReactiveCommand<Unit, Unit> CancelInstall { get; }
|
public ReactiveCommand<Unit, Unit> CancelInstall { get; }
|
||||||
@ -148,6 +156,7 @@ public class ReleaseViewModel : ActivatableViewModelBase
|
|||||||
{
|
{
|
||||||
InstallationInProgress = true;
|
InstallationInProgress = true;
|
||||||
await ReleaseInstaller.InstallAsync(_installerCts.Token);
|
await ReleaseInstaller.InstallAsync(_installerCts.Token);
|
||||||
|
_updateService.QueueUpdate();
|
||||||
InstallationFinished = true;
|
InstallationFinished = true;
|
||||||
}
|
}
|
||||||
catch (TaskCanceledException)
|
catch (TaskCanceledException)
|
||||||
@ -173,7 +182,7 @@ public class ReleaseViewModel : ActivatableViewModelBase
|
|||||||
{
|
{
|
||||||
Loading = true;
|
Loading = true;
|
||||||
|
|
||||||
IOperationResult<IGetReleaseByIdResult> result = await _updatingClient.GetReleaseById.ExecuteAsync(_releaseId, cancellationToken);
|
IOperationResult<IGetReleaseByIdResult> result = await _updatingClient.GetReleaseById.ExecuteAsync(ReleaseId, cancellationToken);
|
||||||
IGetReleaseById_PublishedRelease? release = result.Data?.PublishedRelease;
|
IGetReleaseById_PublishedRelease? release = result.Data?.PublishedRelease;
|
||||||
if (release == null)
|
if (release == null)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -137,6 +137,10 @@ public class SidebarViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
private void NavigateToScreen(SidebarScreenViewModel sidebarScreenViewModel)
|
private void NavigateToScreen(SidebarScreenViewModel sidebarScreenViewModel)
|
||||||
{
|
{
|
||||||
|
// If the current screen changed through external means and already matches, don't navigate again
|
||||||
|
if (_hostScreen.Router.GetCurrentViewModel()?.GetType() == sidebarScreenViewModel.ScreenType)
|
||||||
|
return;
|
||||||
|
|
||||||
_hostScreen.Router.Navigate.Execute(sidebarScreenViewModel.CreateInstance(_container, _hostScreen));
|
_hostScreen.Router.Navigate.Execute(sidebarScreenViewModel.CreateInstance(_container, _hostScreen));
|
||||||
_profileEditorService.ChangeCurrentProfileConfiguration(null);
|
_profileEditorService.ChangeCurrentProfileConfiguration(null);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,5 +4,5 @@ namespace Artemis.UI.Services.Updating;
|
|||||||
|
|
||||||
public interface IUpdateNotificationProvider
|
public interface IUpdateNotificationProvider
|
||||||
{
|
{
|
||||||
Task ShowNotification(string releaseId);
|
Task ShowNotification(string releaseId, string releaseVersion);
|
||||||
}
|
}
|
||||||
@ -11,8 +11,8 @@ public interface IUpdateService : IArtemisUIService
|
|||||||
|
|
||||||
Task CacheLatestRelease();
|
Task CacheLatestRelease();
|
||||||
Task<bool> CheckForUpdate();
|
Task<bool> CheckForUpdate();
|
||||||
Task InstallRelease(string releaseId);
|
|
||||||
void QueueUpdate();
|
void QueueUpdate();
|
||||||
|
|
||||||
ReleaseInstaller GetReleaseInstaller(string releaseId);
|
ReleaseInstaller GetReleaseInstaller(string releaseId);
|
||||||
|
void RestartForUpdate(bool silent);
|
||||||
}
|
}
|
||||||
@ -0,0 +1,66 @@
|
|||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Artemis.UI.Screens.Settings;
|
||||||
|
using Artemis.UI.Shared.Services;
|
||||||
|
using Artemis.UI.Shared.Services.Builders;
|
||||||
|
using Artemis.UI.Shared.Services.MainWindow;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Services.Updating;
|
||||||
|
|
||||||
|
public class InAppUpdateNotificationProvider : IUpdateNotificationProvider
|
||||||
|
{
|
||||||
|
private readonly Func<IScreen, SettingsViewModel> _getSettingsViewModel;
|
||||||
|
private readonly IMainWindowService _mainWindowService;
|
||||||
|
private readonly INotificationService _notificationService;
|
||||||
|
private Action? _notification;
|
||||||
|
|
||||||
|
public InAppUpdateNotificationProvider(INotificationService notificationService, IMainWindowService mainWindowService, Func<IScreen, SettingsViewModel> getSettingsViewModel)
|
||||||
|
{
|
||||||
|
_notificationService = notificationService;
|
||||||
|
_mainWindowService = mainWindowService;
|
||||||
|
_getSettingsViewModel = getSettingsViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ShowInAppNotification(string releaseId, string releaseVersion)
|
||||||
|
{
|
||||||
|
_notification?.Invoke();
|
||||||
|
_notification = _notificationService.CreateNotification()
|
||||||
|
.WithTitle("Update available")
|
||||||
|
.WithMessage($"Artemis version {releaseVersion} has been released")
|
||||||
|
.WithSeverity(NotificationSeverity.Success)
|
||||||
|
.WithTimeout(TimeSpan.FromSeconds(15))
|
||||||
|
.HavingButton(b => b.WithText("View release").WithAction(() => ViewRelease(releaseId)))
|
||||||
|
.Show();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ViewRelease(string releaseId)
|
||||||
|
{
|
||||||
|
_notification?.Invoke();
|
||||||
|
|
||||||
|
if (_mainWindowService.HostScreen == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// TODO: When proper routing has been implemented, use that here
|
||||||
|
// Create a settings VM to navigate to
|
||||||
|
SettingsViewModel settingsViewModel = _getSettingsViewModel(_mainWindowService.HostScreen);
|
||||||
|
// Get the release tab
|
||||||
|
ReleasesTabViewModel releaseTabViewModel = (ReleasesTabViewModel) settingsViewModel.SettingTabs.First(t => t is ReleasesTabViewModel);
|
||||||
|
|
||||||
|
// Navigate to the settings VM
|
||||||
|
_mainWindowService.HostScreen.Router.Navigate.Execute(settingsViewModel);
|
||||||
|
// Navigate to the release tab
|
||||||
|
releaseTabViewModel.PreselectId = releaseId;
|
||||||
|
settingsViewModel.SelectedTab = releaseTabViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public async Task ShowNotification(string releaseId, string releaseVersion)
|
||||||
|
{
|
||||||
|
if (_mainWindowService.IsMainWindowOpen)
|
||||||
|
ShowInAppNotification(releaseId, releaseVersion);
|
||||||
|
else
|
||||||
|
_mainWindowService.MainWindowOpened += (_, _) => ShowInAppNotification(releaseId, releaseVersion);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,12 +0,0 @@
|
|||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Services.Updating;
|
|
||||||
|
|
||||||
public class SimpleUpdateNotificationProvider : IUpdateNotificationProvider
|
|
||||||
{
|
|
||||||
/// <inheritdoc />
|
|
||||||
public async Task ShowNotification(string releaseId)
|
|
||||||
{
|
|
||||||
throw new System.NotImplementedException();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -6,8 +6,6 @@ using Artemis.Core;
|
|||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.Storage.Entities.General;
|
using Artemis.Storage.Entities.General;
|
||||||
using Artemis.Storage.Repositories.Interfaces;
|
using Artemis.Storage.Repositories.Interfaces;
|
||||||
using Artemis.UI.Screens.Settings.Updating;
|
|
||||||
using Artemis.UI.Shared.Services;
|
|
||||||
using Artemis.UI.Shared.Services.MainWindow;
|
using Artemis.UI.Shared.Services.MainWindow;
|
||||||
using Artemis.WebClient.Updating;
|
using Artemis.WebClient.Updating;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
@ -69,7 +67,7 @@ public class UpdateService : IUpdateService
|
|||||||
|
|
||||||
_channel.Value = "feature/gh-actions";
|
_channel.Value = "feature/gh-actions";
|
||||||
_channel.Save();
|
_channel.Save();
|
||||||
|
|
||||||
|
|
||||||
InstallQueuedUpdate();
|
InstallQueuedUpdate();
|
||||||
}
|
}
|
||||||
@ -79,30 +77,21 @@ public class UpdateService : IUpdateService
|
|||||||
if (!_queuedActionRepository.IsTypeQueued("InstallUpdate"))
|
if (!_queuedActionRepository.IsTypeQueued("InstallUpdate"))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Remove the queued action, in case something goes wrong then at least we don't end up in a loop
|
||||||
_queuedActionRepository.ClearByType("InstallUpdate");
|
_queuedActionRepository.ClearByType("InstallUpdate");
|
||||||
|
|
||||||
_logger.Information("Installing queued update");
|
_logger.Information("Installing queued update");
|
||||||
Utilities.ApplyUpdate(false);
|
Utilities.ApplyUpdate(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ShowUpdateDialog(string nextReleaseId)
|
private async Task ShowUpdateNotification(IGetNextRelease_NextPublishedRelease release)
|
||||||
{
|
{
|
||||||
|
await _updateNotificationProvider.Value.ShowNotification(release.Id, release.Version);
|
||||||
|
|
||||||
await Dispatcher.UIThread.InvokeAsync(async () =>
|
|
||||||
{
|
|
||||||
// Main window is probably already open but this will bring it into focus
|
|
||||||
_mainWindowService.OpenMainWindow();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task ShowUpdateNotification(string nextReleaseId)
|
private async Task AutoInstallUpdate(IGetNextRelease_NextPublishedRelease release)
|
||||||
{
|
{
|
||||||
await _updateNotificationProvider.Value.ShowNotification(nextReleaseId);
|
ReleaseInstaller installer = _getReleaseInstaller(release.Id);
|
||||||
}
|
|
||||||
|
|
||||||
private async Task AutoInstallUpdate(string nextReleaseId)
|
|
||||||
{
|
|
||||||
ReleaseInstaller installer = _getReleaseInstaller(nextReleaseId);
|
|
||||||
await installer.InstallAsync(CancellationToken.None);
|
await installer.InstallAsync(CancellationToken.None);
|
||||||
Utilities.ApplyUpdate(true);
|
Utilities.ApplyUpdate(true);
|
||||||
}
|
}
|
||||||
@ -121,7 +110,7 @@ public class UpdateService : IUpdateService
|
|||||||
_logger.Warning(ex, "Auto update failed");
|
_logger.Warning(ex, "Auto update failed");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IGetNextRelease_NextPublishedRelease? CachedLatestRelease { get; private set; }
|
public IGetNextRelease_NextPublishedRelease? CachedLatestRelease { get; private set; }
|
||||||
|
|
||||||
public string? CurrentVersion
|
public string? CurrentVersion
|
||||||
@ -139,12 +128,12 @@ public class UpdateService : IUpdateService
|
|||||||
IOperationResult<IGetNextReleaseResult> result = await _updatingClient.GetNextRelease.ExecuteAsync(CurrentVersion, _channel.Value, _updatePlatform);
|
IOperationResult<IGetNextReleaseResult> result = await _updatingClient.GetNextRelease.ExecuteAsync(CurrentVersion, _channel.Value, _updatePlatform);
|
||||||
CachedLatestRelease = result.Data?.NextPublishedRelease;
|
CachedLatestRelease = result.Data?.NextPublishedRelease;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> CheckForUpdate()
|
public async Task<bool> CheckForUpdate()
|
||||||
{
|
{
|
||||||
IOperationResult<IGetNextReleaseResult> result = await _updatingClient.GetNextRelease.ExecuteAsync(CurrentVersion, _channel.Value, _updatePlatform);
|
IOperationResult<IGetNextReleaseResult> result = await _updatingClient.GetNextRelease.ExecuteAsync(CurrentVersion, _channel.Value, _updatePlatform);
|
||||||
result.EnsureNoErrors();
|
result.EnsureNoErrors();
|
||||||
|
|
||||||
// Update cache
|
// Update cache
|
||||||
CachedLatestRelease = result.Data?.NextPublishedRelease;
|
CachedLatestRelease = result.Data?.NextPublishedRelease;
|
||||||
|
|
||||||
@ -156,27 +145,14 @@ public class UpdateService : IUpdateService
|
|||||||
_suspendAutoCheck = true;
|
_suspendAutoCheck = true;
|
||||||
|
|
||||||
// If the window is open show the changelog, don't auto-update while the user is busy
|
// If the window is open show the changelog, don't auto-update while the user is busy
|
||||||
if (_mainWindowService.IsMainWindowOpen)
|
if (!_autoInstall.Value)
|
||||||
await ShowUpdateDialog(CachedLatestRelease.Id);
|
await ShowUpdateNotification(CachedLatestRelease);
|
||||||
else if (!_autoInstall.Value)
|
|
||||||
await ShowUpdateNotification(CachedLatestRelease.Id);
|
|
||||||
else
|
else
|
||||||
await AutoInstallUpdate(CachedLatestRelease.Id);
|
await AutoInstallUpdate(CachedLatestRelease);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public async Task InstallRelease(string releaseId)
|
|
||||||
{
|
|
||||||
ReleaseInstaller installer = _getReleaseInstaller(releaseId);
|
|
||||||
await Dispatcher.UIThread.InvokeAsync(() =>
|
|
||||||
{
|
|
||||||
// Main window is probably already open but this will bring it into focus
|
|
||||||
_mainWindowService.OpenMainWindow();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void QueueUpdate()
|
public void QueueUpdate()
|
||||||
{
|
{
|
||||||
@ -184,9 +160,22 @@ public class UpdateService : IUpdateService
|
|||||||
_queuedActionRepository.Add(new QueuedActionEntity {Type = "InstallUpdate"});
|
_queuedActionRepository.Add(new QueuedActionEntity {Type = "InstallUpdate"});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void DequeueUpdate()
|
||||||
|
{
|
||||||
|
_queuedActionRepository.ClearByType("InstallUpdate");
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ReleaseInstaller GetReleaseInstaller(string releaseId)
|
public ReleaseInstaller GetReleaseInstaller(string releaseId)
|
||||||
{
|
{
|
||||||
return _getReleaseInstaller(releaseId);
|
return _getReleaseInstaller(releaseId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void RestartForUpdate(bool silent)
|
||||||
|
{
|
||||||
|
DequeueUpdate();
|
||||||
|
Utilities.ApplyUpdate(silent);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user