Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 12 additions & 2 deletions src/SwitchifyPc.App/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,7 @@ private Window CreateMainWindow()
mainWindowViewModel,
ShowSettingsWindow,
ShowSetupGuideWindow,
ShowSettingsWindow,
InstallAvailableUpdateAsync,
DisconnectBluetoothDevices,
AcceptPairingApprovalAsync,
RejectPairingApproval);
Expand Down Expand Up @@ -325,6 +325,12 @@ private UpdateService CreateUpdateService()
OnStateChanged: UpdateMainWindowState));
}

private Task<UpdateApplyResult> InstallAvailableUpdateAsync()
{
return updateService?.InstallAvailableUpdateAsync()
?? Task.FromResult(UpdateApplyResult.DownloadFailure(UpdateFailureReason.NotAvailable));
}

private PairingApprovalManager CreatePairingApprovalManager()
{
return new PairingApprovalManager(new JsonPairingStore(Path.Combine(UserDataDirectory(), "pairing-state.json")));
Expand Down Expand Up @@ -743,7 +749,11 @@ private static bool IsInstalledApp()
private void UpdateMainWindowState(UpdateState state)
{
RecordUpdateStateDiagnostic(state);
Dispatcher.BeginInvoke(() => mainWindowViewModel.SetUpdateState(state));
Dispatcher.BeginInvoke(() =>
{
mainWindowViewModel.SetUpdateState(state);
settingsWindow?.ApplyUpdateState(state);
});
}

private void UpdateBluetoothState(BluetoothStatus status)
Expand Down
3 changes: 2 additions & 1 deletion src/SwitchifyPc.App/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -314,7 +314,8 @@
<Button Grid.Column="1"
Margin="16,0,0,0"
Content="{Binding UpdateBannerButtonText}"
Click="OpenUpdates_Click" />
IsEnabled="{Binding IsUpdateBannerButtonEnabled}"
Click="InstallUpdate_Click" />
</Grid>
</Border>

Expand Down
42 changes: 37 additions & 5 deletions src/SwitchifyPc.App/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
@@ -1,29 +1,32 @@
using System.Windows;
using SwitchifyPc.Core.Ui;
using SwitchifyPc.Core.Updates;
using WpfMessageBox = System.Windows.MessageBox;

namespace SwitchifyPc.App;

public partial class MainWindow : Window
{
private readonly Action? openSettings;
private readonly Action? openSetupGuide;
private readonly Action? openUpdates;
private readonly Func<Task<UpdateApplyResult>>? installUpdate;
private readonly Action? disconnectDevices;
private readonly Func<string, Task>? acceptPairingApproval;
private readonly Action<string>? rejectPairingApproval;
private bool isInstallingUpdate;

public MainWindow(
MainWindowViewModel? viewModel = null,
Action? openSettings = null,
Action? openSetupGuide = null,
Action? openUpdates = null,
Func<Task<UpdateApplyResult>>? installUpdate = null,
Action? disconnectDevices = null,
Func<string, Task>? acceptPairingApproval = null,
Action<string>? rejectPairingApproval = null)
{
this.openSettings = openSettings;
this.openSetupGuide = openSetupGuide;
this.openUpdates = openUpdates;
this.installUpdate = installUpdate;
this.disconnectDevices = disconnectDevices;
this.acceptPairingApproval = acceptPairingApproval;
this.rejectPairingApproval = rejectPairingApproval;
Expand All @@ -41,9 +44,38 @@ private void OpenSetupGuide_Click(object sender, RoutedEventArgs e)
openSetupGuide?.Invoke();
}

private void OpenUpdates_Click(object sender, RoutedEventArgs e)
private async void InstallUpdate_Click(object sender, RoutedEventArgs e)
{
openUpdates?.Invoke();
if (installUpdate is null || isInstallingUpdate) return;

isInstallingUpdate = true;
try
{
UpdateApplyResult result = await installUpdate();
if (!result.Ok)
{
WpfMessageBox.Show(
UpdateUiCopy.ApplyFailureMessage(result),
"Update installer",
MessageBoxButton.OK,
MessageBoxImage.Warning);
}
}
catch (OperationCanceledException)
{
}
catch
{
WpfMessageBox.Show(
"The update could not be installed.",
"Update installer",
MessageBoxButton.OK,
MessageBoxImage.Warning);
}
finally
{
isInstallingUpdate = false;
}
}

private void Disconnect_Click(object sender, RoutedEventArgs e)
Expand Down
19 changes: 9 additions & 10 deletions src/SwitchifyPc.App/SettingsWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,7 @@
<StackPanel>
<TextBlock Text="Updates" Style="{StaticResource SectionTitle}" />
<TextBlock Margin="0,6,0,0"
Text="Check, download, and open Switchify PC updates."
Text="Check for and install Switchify PC updates."
Style="{StaticResource MutedText}" />
<Border Margin="0,16,0,0" Style="{StaticResource SubtlePanel}">
<StackPanel>
Expand All @@ -744,18 +744,17 @@
Style="{StaticResource MutedText}" />
</StackPanel>
<WrapPanel Margin="0,14,0,0">
<Button Content="Check for updates"
<Button Content="{Binding UpdateCheckActionText}"
Margin="0,0,10,8"
Click="CheckForUpdates_Click" />
<Button Content="Download update"
Click="CheckForUpdates_Click"
IsEnabled="{Binding CanCheckForUpdates}"
Visibility="{Binding IsCheckUpdateActionVisible, Converter={StaticResource BooleanToVisibilityConverter}}" />
<Button Content="{Binding UpdatePrimaryActionText}"
Margin="0,0,10,8"
Click="DownloadUpdate_Click"
IsEnabled="{Binding CanDownloadUpdate}" />
<Button Content="Install update"
Margin="0,0,10,8"
Click="InstallUpdate_Click"
Click="InstallAvailableUpdate_Click"
Style="{StaticResource PrimaryButton}"
IsEnabled="{Binding CanInstallUpdate}" />
IsEnabled="{Binding CanRunUpdatePrimaryAction}"
Visibility="{Binding IsInstallUpdateActionVisible, Converter={StaticResource BooleanToVisibilityConverter}}" />
</WrapPanel>
</StackPanel>
</Border>
Expand Down
50 changes: 31 additions & 19 deletions src/SwitchifyPc.App/SettingsWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public partial class SettingsWindow : Window
private bool isLoaded;
private bool isApplyingSettings;
private bool settingsLoaded;
private bool isInstallingUpdate;

public SettingsWindow(SettingsController controller) : this(controller.ViewModel)
{
Expand Down Expand Up @@ -190,30 +191,41 @@ await RunActionAsync(
"Updates could not be checked.");
}

private async void DownloadUpdate_Click(object sender, RoutedEventArgs e)
private async void InstallAvailableUpdate_Click(object sender, RoutedEventArgs e)
{
if (controller is null) return;
await RunActionAsync(
() => controller.DownloadUpdateAsync(),
"The update could not be downloaded.");
if (controller is null || isInstallingUpdate) return;

isInstallingUpdate = true;
try
{
await RunActionAsync(async () =>
{
UpdateApplyResult result = await controller.InstallAvailableUpdateAsync();
if (!result.Ok)
{
WpfMessageBox.Show(
UpdateUiCopy.ApplyFailureMessage(result),
"Update installer",
MessageBoxButton.OK,
MessageBoxImage.Warning);
}
}, "The update could not be installed.");
}
finally
{
isInstallingUpdate = false;
}
}

private async void InstallUpdate_Click(object sender, RoutedEventArgs e)
public void ApplyUpdateState(UpdateState state)
{
if (controller is null) return;

await RunActionAsync(async () =>
if (!Dispatcher.CheckAccess())
{
UpdateInstallResult result = await controller.InstallDownloadedUpdateAsync();
if (!result.Ok)
{
WpfMessageBox.Show(
SettingsViewModel.InstallMessage(result.Reason),
"Update installer",
MessageBoxButton.OK,
MessageBoxImage.Warning);
}
}, "The update installer could not be opened.");
Dispatcher.BeginInvoke(() => ApplyUpdateState(state));
return;
}

controller?.ApplyUpdateState(state);
}

private void SaveIfReady(Action save)
Expand Down
50 changes: 46 additions & 4 deletions src/SwitchifyPc.Core/Ui/MainWindowCopy.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ public enum DesktopUiState

public sealed record BluetoothPrimaryCopy(string Title, string Body, string Tone);

public sealed record UpdateBannerCopy(string Title, string Body, string Tone, string ButtonText);
public sealed record UpdateBannerCopy(string Title, string Body, string Tone, string ButtonText, bool ButtonEnabled);

public static class MainWindowCopy
{
Expand Down Expand Up @@ -249,22 +249,64 @@ public static string BluetoothRecentError(BluetoothStatus? status)
public static UpdateBannerCopy? UpdateBanner(UpdateState? state)
{
if (state is null) return null;
if (state.IsApplyingUpdate && state.Download.Status == UpdateDownloadStatus.Downloaded)
{
return new UpdateBannerCopy(
"Installing update...",
"The update installer is opening. Switchify PC will restart when installation finishes.",
"downloaded",
"Installing...",
false);
}

if (state.Download.Status == UpdateDownloadStatus.Downloading)
{
return new UpdateBannerCopy(
"Downloading update...",
"Switchify PC is downloading the update.",
"available",
"Downloading...",
false);
}

if (state.LastApplyResult is { Ok: false, FailureStage: UpdateApplyFailureStage.Install } failure)
{
return new UpdateBannerCopy(
"Update installation failed",
UpdateUiCopy.ApplyFailureMessage(failure),
"available",
"Retry update",
!state.IsApplyingUpdate);
}

if (state.Download.Status == UpdateDownloadStatus.DownloadFailed)
{
return new UpdateBannerCopy(
"Update download failed",
"The update could not be downloaded. Try again.",
"available",
"Retry update",
!state.IsApplyingUpdate);
}

if (state.Download.Status == UpdateDownloadStatus.Downloaded)
{
return new UpdateBannerCopy(
"Update ready to install",
"The update has been downloaded and is ready to install.",
"downloaded",
"Open updates");
"Install update",
!state.IsApplyingUpdate);
}

if (state.Info.Status == UpdateCheckStatus.UpdateAvailable)
{
return new UpdateBannerCopy(
"Update available",
"A new Switchify PC update is ready to download.",
"A new Switchify PC update is ready to install.",
"available",
"Open updates");
"Install update",
!state.IsApplyingUpdate);
}

return null;
Expand Down
5 changes: 4 additions & 1 deletion src/SwitchifyPc.Core/Ui/MainWindowViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ public sealed class MainWindowViewModel : INotifyPropertyChanged

public string UpdateBannerBody => MainWindowCopy.UpdateBanner(updateState)?.Body ?? "";

public string UpdateBannerButtonText => MainWindowCopy.UpdateBanner(updateState)?.ButtonText ?? "Open updates";
public string UpdateBannerButtonText => MainWindowCopy.UpdateBanner(updateState)?.ButtonText ?? "Install update";

public bool IsUpdateBannerButtonEnabled => MainWindowCopy.UpdateBanner(updateState)?.ButtonEnabled ?? false;

public string UpdateBannerTone => MainWindowCopy.UpdateBanner(updateState)?.Tone ?? "";

Expand All @@ -83,6 +85,7 @@ public void SetUpdateState(UpdateState state)
OnPropertyChanged(nameof(UpdateBannerTitle));
OnPropertyChanged(nameof(UpdateBannerBody));
OnPropertyChanged(nameof(UpdateBannerButtonText));
OnPropertyChanged(nameof(IsUpdateBannerButtonEnabled));
OnPropertyChanged(nameof(UpdateBannerTone));
}

Expand Down
7 changes: 7 additions & 0 deletions src/SwitchifyPc.Core/Ui/SettingsController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ public async Task<UpdateInstallResult> InstallDownloadedUpdateAsync(Cancellation
return result;
}

public async Task<UpdateApplyResult> InstallAvailableUpdateAsync(CancellationToken cancellationToken = default)
{
UpdateApplyResult result = await updates.InstallAvailableUpdateAsync(cancellationToken).ConfigureAwait(false);
viewModel.SetUpdateState(updates.GetState());
return result;
}

public void ApplyUpdateState(UpdateState state)
{
viewModel.SetUpdateState(state);
Expand Down
Loading