Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Display release notes after updating app #10976

Merged
merged 15 commits into from
Jan 11, 2023
1 change: 1 addition & 0 deletions src/Files.App/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,7 @@ await Task.WhenAll(
var updateService = Ioc.Default.GetRequiredService<IUpdateService>();
await updateService.CheckForUpdates();
await updateService.DownloadMandatoryUpdates();
await updateService.CheckLatestReleaseNotesAsync();

static async Task OptionalTask(Task task, bool condition)
{
Expand Down
39 changes: 34 additions & 5 deletions src/Files.App/ServicesImplementation/SideloadUpdateService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Diagnostics;
using System.IO;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Serialization;
using Windows.ApplicationModel;
Expand Down Expand Up @@ -55,13 +56,17 @@ public bool IsUpdating
private set => SetProperty(ref _isUpdating, value);
}

private bool _isAppUpdated;
public bool IsAppUpdated
{
get => _isAppUpdated;
private set => SetProperty(ref _isAppUpdated, value);
get => SystemInformation.Instance.IsAppUpdated;
}

private bool _isReleaseNotesAvailable;
public bool IsReleaseNotesAvailable
{
get => _isReleaseNotesAvailable;
private set => SetProperty(ref _isReleaseNotesAvailable, value);
}
public async Task DownloadUpdates()
{
await ApplyPackageUpdate();
Expand All @@ -72,9 +77,33 @@ public Task DownloadMandatoryUpdates()
return Task.CompletedTask;
}

public SideloadUpdateService()
public async Task<string?> GetLatestReleaseNotesAsync(CancellationToken cancellationToken = default)
{
var applicationVersion = $"{SystemInformation.Instance.ApplicationVersion.Major}.{SystemInformation.Instance.ApplicationVersion.Minor}.{SystemInformation.Instance.ApplicationVersion.Build}";
var releaseNotesLocation = string.Concat("https://raw.githubusercontent.com/files-community/Release-Notes/main/", applicationVersion, ".md");

using (var client = new HttpClient())
{
try
{
var result = await client.GetStringAsync(releaseNotesLocation, cancellationToken);
return result == string.Empty ? null : result;
}
catch
{
return null;
}
}
}

public async Task CheckLatestReleaseNotesAsync(CancellationToken cancellationToken = default)
{
IsAppUpdated = SystemInformation.Instance.IsAppUpdated;
if (!IsAppUpdated)
return;

var result = await GetLatestReleaseNotesAsync();
if (result is not null)
IsReleaseNotesAvailable = true;
}

public async Task CheckForUpdates()
Expand Down
45 changes: 40 additions & 5 deletions src/Files.App/ServicesImplementation/UpdateService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Windows.Services.Store;
using WinRT.Interop;
Expand Down Expand Up @@ -34,18 +36,21 @@ public bool IsUpdating
private set => SetProperty(ref _isUpdating, value);
}

private bool _isAppUpdated;
private bool _isReleaseNotesAvailable;
public bool IsReleaseNotesAvailable
{
get => _isReleaseNotesAvailable;
private set => SetProperty(ref _isReleaseNotesAvailable, value);
}

public bool IsAppUpdated
{
get => _isAppUpdated;
private set => SetProperty(ref _isAppUpdated, value);
get => SystemInformation.Instance.IsAppUpdated;
}

public UpdateService()
{
_updatePackages = new List<StorePackageUpdate>();

IsAppUpdated = SystemInformation.Instance.IsAppUpdated;
}

public async Task DownloadUpdates()
Expand Down Expand Up @@ -143,6 +148,36 @@ private static async Task<bool> ShowDialogAsync()
return result == ContentDialogResult.Primary;
}

public async Task CheckLatestReleaseNotesAsync(CancellationToken cancellationToken = default)
{
if (!IsAppUpdated)
return;

var result = await GetLatestReleaseNotesAsync();

if (result is not null)
IsReleaseNotesAvailable = true;
}

public async Task<string?> GetLatestReleaseNotesAsync(CancellationToken cancellationToken = default)
{
var applicationVersion = $"{SystemInformation.Instance.ApplicationVersion.Major}.{SystemInformation.Instance.ApplicationVersion.Minor}.{SystemInformation.Instance.ApplicationVersion.Build}";
var releaseNotesLocation = string.Concat("https://raw.githubusercontent.com/files-community/Release-Notes/main/", applicationVersion, ".md");

using (var client = new HttpClient())
{
try
{
var result = await client.GetStringAsync(releaseNotesLocation, cancellationToken);
return result == string.Empty ? null : result;
}
catch
{
return null;
}
}
}

// WINUI3
private static ContentDialog SetContentDialogRoot(ContentDialog contentDialog)
{
Expand Down
20 changes: 10 additions & 10 deletions src/Files.App/UserControls/AddressToolbar.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -265,18 +265,18 @@
x:Name="UpdateButton"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
x:Load="{x:Bind ViewModel.UpdateService.IsUpdateAvailable, Mode=OneWay}"
x:Load="{x:Bind ViewModel.IsUpdateAvailable, Mode=OneWay}"
AccessKey="1"
AutomationProperties.Name="{helpers:ResourceString Name=UpdateFiles}"
Command="{x:Bind ViewModel.UpdateCommand, Mode=OneWay}"
IsEnabled="{x:Bind ViewModel.UpdateService.IsUpdating, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"
IsEnabled="{x:Bind ViewModel.IsUpdating, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"
Style="{StaticResource AddressToolbarButtonStyle}"
ToolTipService.ToolTip="{helpers:ResourceString Name=UpdateFiles}">
<Grid>
<!-- Icon -->
<FontIcon
x:Name="UpdateIcon"
x:Load="{x:Bind ViewModel.UpdateService.IsUpdating, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"
x:Load="{x:Bind ViewModel.IsUpdating, Mode=OneWay, Converter={StaticResource BoolNegationConverter}}"
FontSize="14"
Foreground="{ThemeResource SystemAccentColor}"
Glyph="&#xE896;" />
Expand All @@ -286,7 +286,7 @@
x:Name="UpdateProgressRing"
Width="20"
Height="20"
x:Load="{x:Bind ViewModel.UpdateService.IsUpdating, Mode=OneWay}"
x:Load="{x:Bind ViewModel.IsUpdating, Mode=OneWay}"
IsIndeterminate="True" />
</Grid>
</Button>
Expand All @@ -296,7 +296,7 @@
x:Name="ViewReleaseNotesButton"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
x:Load="{x:Bind ViewModel.UpdateService.IsAppUpdated, Mode=OneWay}"
x:Load="{x:Bind ViewModel.IsReleaseNotesVisible, Mode=OneWay}"
AccessKey="2"
AutomationProperties.Name="{helpers:ResourceString Name=ReleaseNotes}"
Command="{x:Bind ViewModel.ViewReleaseNotesCommand, Mode=OneWay}"
Expand Down Expand Up @@ -338,7 +338,6 @@
<!-- Release Notes Teaching Tip -->
<TeachingTip
x:Name="ReleaseNotesTeachingTip"
Title="{helpers:ResourceString Name=ReleaseNotes}"
IsLightDismissEnabled="True"
IsOpen="{x:Bind ViewModel.IsReleaseNotesOpen, Mode=TwoWay}"
Target="{x:Bind ViewReleaseNotesButton}">
Expand All @@ -361,13 +360,14 @@
<!-- Markdown Content -->
<TeachingTip.Content>
<ScrollViewer
Width="260"
Height="240"
HorizontalScrollMode="Disabled"
VerticalScrollMode="Enabled">
HorizontalScrollMode="Auto"
VerticalScrollMode="Auto">
<controls:MarkdownTextBlock
Padding="0,12"
Background="Transparent"
Text="Coming Soon 👀" />
ListGutterWidth="16"
Text="{x:Bind ViewModel.ReleaseNotes, Mode=OneWay}" />
</ScrollViewer>
</TeachingTip.Content>
</TeachingTip>
Expand Down
68 changes: 60 additions & 8 deletions src/Files.App/ViewModels/ToolbarViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using Files.App.Filesystem;
using Files.App.Filesystem.StorageItems;
using Files.App.Helpers;
using Files.App.ServicesImplementation;
using Files.App.Shell;
using Files.App.UserControls;
using Files.App.Views;
Expand All @@ -23,10 +24,13 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
using System.Windows.Input;
using Vanara.PInvoke;
using Windows.ApplicationModel.DataTransfer;
using Windows.Storage;
using Windows.UI.Text;
Expand All @@ -40,7 +44,6 @@ namespace Files.App.ViewModels
public class ToolbarViewModel : ObservableObject, IAddressToolbar, IDisposable
{
private IUserSettingsService UserSettingsService { get; } = Ioc.Default.GetRequiredService<IUserSettingsService>();

public IUpdateService UpdateService { get; } = Ioc.Default.GetService<IUpdateService>()!;

public delegate void ToolbarPathItemInvokedEventHandler(object sender, PathNavigationEventArgs e);
Expand Down Expand Up @@ -252,6 +255,41 @@ public bool IsLayoutAdaptive
public bool IsAdaptiveLayoutEnabled
=> UserSettingsService.FoldersSettingsService.EnableOverridingFolderPreferences;

private bool isUpdating;
public bool IsUpdating
{
get => isUpdating;
set => SetProperty(ref isUpdating, value);
}

private bool isUpdateAvailable;
public bool IsUpdateAvailable
{
get => isUpdateAvailable;
set => SetProperty(ref isUpdateAvailable, value);
}

private string? releaseNotes;
public string? ReleaseNotes
{
get => releaseNotes;
set => SetProperty(ref releaseNotes, value);
}

private bool isReleaseNotesVisible;
public bool IsReleaseNotesVisible
{
get => isReleaseNotesVisible;
set => SetProperty(ref isReleaseNotesVisible, value);
}

private bool isReleaseNotesOpen;
public bool IsReleaseNotesOpen
{
get => isReleaseNotesOpen;
set => SetProperty(ref isReleaseNotesOpen, value);
}

private bool canCopyPathInPage;
public bool CanCopyPathInPage
{
Expand Down Expand Up @@ -312,13 +350,6 @@ public bool IsSearchBoxVisible
}
}

private bool isReleaseNotesOpen;
public bool IsReleaseNotesOpen
{
get => isReleaseNotesOpen;
set => SetProperty(ref isReleaseNotesOpen, value);
}

private string? pathText;
public string? PathText
{
Expand Down Expand Up @@ -379,12 +410,33 @@ public ToolbarViewModel()

SearchBox.Escaped += SearchRegion_Escaped;
UserSettingsService.OnSettingChangedEvent += UserSettingsService_OnSettingChangedEvent;
UpdateService.PropertyChanged += UpdateService_OnPropertyChanged;
}

private async void UpdateService_OnPropertyChanged(object? sender, PropertyChangedEventArgs e)
{
IsUpdateAvailable = UpdateService.IsUpdateAvailable;
IsUpdating = UpdateService.IsUpdating;

// Bad code, result is called twice when checking for release notes
if (UpdateService.IsReleaseNotesAvailable)
await CheckForReleaseNotesAsync();
}

private void DoViewReleaseNotes()
{
IsReleaseNotesOpen = true;
}

public async Task CheckForReleaseNotesAsync()
{
var result = await UpdateService.GetLatestReleaseNotesAsync();
if (result is null)
return;

ReleaseNotes = result;
IsReleaseNotesVisible = true;
}

private void UserSettingsService_OnSettingChangedEvent(object? sender, SettingChangedEventArgs e)
{
Expand Down
17 changes: 16 additions & 1 deletion src/Files.Backend/Services/IUpdateService.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
using System.ComponentModel;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;

namespace Files.Backend.Services
Expand All @@ -20,10 +23,22 @@ public interface IUpdateService : INotifyPropertyChanged
/// </summary>
bool IsAppUpdated { get; }

/// <summary>
/// Gets a value indicating if release notes are available.
/// </summary>
bool IsReleaseNotesAvailable { get; }

Task DownloadUpdates();

Task DownloadMandatoryUpdates();

Task CheckForUpdates();

Task CheckLatestReleaseNotesAsync(CancellationToken cancellationToken = default);

/// <summary>
/// Gets release notes for the latest release
/// </summary>
Task<string?> GetLatestReleaseNotesAsync(CancellationToken cancellationToken = default);
}
}