diff --git a/src/Files/App.xaml.cs b/src/Files/App.xaml.cs index 2c1685a04919..b6fe711ae0cf 100644 --- a/src/Files/App.xaml.cs +++ b/src/Files/App.xaml.cs @@ -106,6 +106,7 @@ private IServiceProvider ConfigureServices() // Settings not related to IUserSettingsService: .AddSingleton() .AddSingleton() + .AddSingleton() // TODO: Dialogs: @@ -183,7 +184,9 @@ await Task.WhenAll( }); // Check for required updates - new AppUpdater().CheckForUpdatesAsync(); + var updateService = Ioc.Default.GetRequiredService(); + await updateService.CheckForUpdates(); + await updateService.DownloadMandatoryUpdates(); } private void OnLeavingBackground(object sender, LeavingBackgroundEventArgs e) diff --git a/src/Files/Files.csproj b/src/Files/Files.csproj index deffb0a80c24..4c52f588b18b 100644 --- a/src/Files/Files.csproj +++ b/src/Files/Files.csproj @@ -264,8 +264,10 @@ + + ColoredIcon.xaml diff --git a/src/Files/Services/IUpdateSettingsService.cs b/src/Files/Services/IUpdateSettingsService.cs new file mode 100644 index 000000000000..c4f29f901603 --- /dev/null +++ b/src/Files/Services/IUpdateSettingsService.cs @@ -0,0 +1,25 @@ +using System; +using System.ComponentModel; +using System.Threading.Tasks; + +namespace Files.Services +{ + public interface IUpdateSettingsService : IBaseSettingsService, INotifyPropertyChanged + { + /// + /// Gets a value indicating whether updates are available. + /// + bool IsUpdateAvailable { get; } + + /// + /// Gets a value indicating if an update is in progress. + /// + bool IsUpdating { get; } + + Task DownloadUpdates(); + + Task DownloadMandatoryUpdates(); + + Task CheckForUpdates(); + } +} diff --git a/src/Files/Services/Implementation/UpdateSettingsService.cs b/src/Files/Services/Implementation/UpdateSettingsService.cs new file mode 100644 index 000000000000..fdbc7a6e4bbe --- /dev/null +++ b/src/Files/Services/Implementation/UpdateSettingsService.cs @@ -0,0 +1,161 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Threading.Tasks; +using Files.Models.JsonSettings; +using Microsoft.Toolkit.Uwp; +using Windows.Services.Store; +using Windows.UI.Xaml.Controls; + +namespace Files.Services.Implementation +{ + public class UpdateSettingsService : BaseObservableJsonSettingsModel, IUpdateSettingsService + { + private StoreContext _storeContext; + private IList _updatePackages; + + private bool IsMandatory => _updatePackages?.Where(e => e.Mandatory).ToList().Count >= 1; + + private bool _isUpdateAvailable; + + public bool IsUpdateAvailable + { + get => _isUpdateAvailable; + set + { + _isUpdateAvailable = value; + OnPropertyChanged(nameof(IsUpdateAvailable)); + } + } + + private bool _isUpdating; + + public bool IsUpdating + { + get => _isUpdating; + private set + { + _isUpdating = value; + OnPropertyChanged(nameof(IsUpdating)); + } + } + + public UpdateSettingsService() + { + _updatePackages = new List(); + } + + public void ReportToAppCenter() {} + + public async Task DownloadUpdates() + { + OnUpdateInProgress(); + + if (!HasUpdates()) + { + return; + } + + // double check for Mandatory + if (IsMandatory) + { + // Show dialog + var dialog = await ShowDialogAsync(); + if (!dialog) + { + // User rejected mandatory update. + OnUpdateCancelled(); + return; + } + } + + await DownloadAndInstall(); + OnUpdateCompleted(); + } + + public async Task DownloadMandatoryUpdates() + { + // Prompt the user to download if the package list + // contains mandatory updates. + if (IsMandatory && HasUpdates()) + { + if (await ShowDialogAsync()) + { + OnUpdateInProgress(); + await DownloadAndInstall(); + OnUpdateCompleted(); + } + } + } + + public async Task CheckForUpdates() + { + await GetUpdatePackages(); + + if (_updatePackages is not null && _updatePackages.Count > 0) + { + IsUpdateAvailable = true; + } + } + + private async Task DownloadAndInstall() + { + App.SaveSessionTabs(); + var downloadOperation = _storeContext.RequestDownloadAndInstallStorePackageUpdatesAsync(_updatePackages); + await downloadOperation.AsTask(); + } + + private async Task GetUpdatePackages() + { + try + { + _storeContext ??= await Task.Run(StoreContext.GetDefault); + var updateList = await _storeContext.GetAppAndOptionalStorePackageUpdatesAsync(); + _updatePackages = updateList?.ToList(); + } + catch (FileNotFoundException) + { + // Suppress the FileNotFoundException. + // GetAppAndOptionalStorePackageUpdatesAsync throws for unknown reasons. + } + } + + private static async Task ShowDialogAsync() + { + //TODO: Use IDialogService in future. + ContentDialog dialog = new() + { + Title = "ConsentDialogTitle".GetLocalized(), + Content = "ConsentDialogContent".GetLocalized(), + CloseButtonText = "Close".GetLocalized(), + PrimaryButtonText = "ConsentDialogPrimaryButtonText".GetLocalized() + }; + ContentDialogResult result = await dialog.ShowAsync(); + + return result == ContentDialogResult.Primary; + } + + private bool HasUpdates() + { + return _updatePackages is not null && _updatePackages.Count >= 1; + } + + protected virtual void OnUpdateInProgress() + { + IsUpdating = true; + } + + protected virtual void OnUpdateCompleted() + { + IsUpdating = false; + IsUpdateAvailable = false; + _updatePackages.Clear(); + } + + protected virtual void OnUpdateCancelled() + { + IsUpdating = false; + } + } +} diff --git a/src/Files/Strings/en-US/Resources.resw b/src/Files/Strings/en-US/Resources.resw index d4ba878cf64e..9f76b38eefb5 100644 --- a/src/Files/Strings/en-US/Resources.resw +++ b/src/Files/Strings/en-US/Resources.resw @@ -2744,4 +2744,7 @@ We use App Center to track which settings are being used, find bugs, and fix cra Close others - + + Update Files + + \ No newline at end of file diff --git a/src/Files/UserControls/NavigationToolbar.xaml b/src/Files/UserControls/NavigationToolbar.xaml index b6f08ea5f2a6..e45a6dcec406 100644 --- a/src/Files/UserControls/NavigationToolbar.xaml +++ b/src/Files/UserControls/NavigationToolbar.xaml @@ -562,6 +562,22 @@ Value="{x:Bind OngoingTasksViewModel.InfoBadgeValue, Mode=OneWay}" /> + +