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

Update theme of Add Widget dialog when system theme changes #2407

Merged
merged 9 commits into from
Mar 20, 2024
32 changes: 28 additions & 4 deletions tools/Dashboard/DevHome.Dashboard/ViewModels/AddWidgetViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@

using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using DevHome.Contracts.Services;
using DevHome.Dashboard.Services;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
using Microsoft.Windows.Widgets.Hosts;

Expand All @@ -13,6 +14,7 @@ namespace DevHome.Dashboard.ViewModels;
public partial class AddWidgetViewModel : ObservableObject
{
private readonly IWidgetScreenshotService _widgetScreenshotService;
private readonly IThemeSelectorService _themeSelectorService;

[ObservableProperty]
private string _widgetDisplayTitle;
Expand All @@ -26,14 +28,20 @@ public partial class AddWidgetViewModel : ObservableObject
[ObservableProperty]
private bool _pinButtonVisibility;

public AddWidgetViewModel(IWidgetScreenshotService widgetScreenshotService)
private WidgetDefinition _selectedWidgetDefinition;

public AddWidgetViewModel(
IWidgetScreenshotService widgetScreenshotService,
IThemeSelectorService themeSelectorService)
{
_widgetScreenshotService = widgetScreenshotService;
_themeSelectorService = themeSelectorService;
}

public async Task SetWidgetDefinition(WidgetDefinition selectedWidgetDefinition, ElementTheme actualTheme)
public async Task SetWidgetDefinition(WidgetDefinition selectedWidgetDefinition)
{
var bitmap = await _widgetScreenshotService.GetScreenshotFromCache(selectedWidgetDefinition, actualTheme);
_selectedWidgetDefinition = selectedWidgetDefinition;
var bitmap = await _widgetScreenshotService.GetScreenshotFromCache(selectedWidgetDefinition, _themeSelectorService.GetActualTheme());

WidgetDisplayTitle = selectedWidgetDefinition.DisplayTitle;
WidgetProviderDisplayTitle = selectedWidgetDefinition.ProviderDefinition.DisplayName;
Expand All @@ -50,5 +58,21 @@ public void Clear()
WidgetProviderDisplayTitle = string.Empty;
WidgetScreenshot = null;
PinButtonVisibility = false;
_selectedWidgetDefinition = null;
}

[RelayCommand]
private async Task UpdateThemeAsync()
{
if (_selectedWidgetDefinition != null)
{
// Update the preview image for the selected widget.
var theme = _themeSelectorService.GetActualTheme();
var bitmap = await _widgetScreenshotService.GetScreenshotFromCache(_selectedWidgetDefinition, theme);
WidgetScreenshot = new ImageBrush
{
ImageSource = bitmap,
};
}
}
}
7 changes: 4 additions & 3 deletions tools/Dashboard/DevHome.Dashboard/Views/AddWidgetDialog.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,19 @@
x:Class="DevHome.Dashboard.Views.AddWidgetDialog"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:commonviews="using:DevHome.Common.Views"
xmlns:i="using:Microsoft.Xaml.Interactivity"
xmlns:ic="using:Microsoft.Xaml.Interactions.Core"
mc:Ignorable="d"
Style="{StaticResource DefaultContentDialogStyle}"
SizeChanged="ContentDialog_SizeChanged">
<i:Interaction.Behaviors>
<ic:EventTriggerBehavior EventName="Loaded">
<ic:InvokeCommandAction Command="{x:Bind LoadedCommand}" />
</ic:EventTriggerBehavior>
<ic:EventTriggerBehavior EventName="ActualThemeChanged">
<ic:InvokeCommandAction Command="{x:Bind ViewModel.UpdateThemeCommand}" />
<ic:InvokeCommandAction Command="{x:Bind UpdateThemeCommand}" />
</ic:EventTriggerBehavior>
</i:Interaction.Behaviors>

<!-- ContentDialog Width and Height are not properly hooked up and must be set this way -->
Expand Down
42 changes: 29 additions & 13 deletions tools/Dashboard/DevHome.Dashboard/Views/AddWidgetDialog.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,47 +6,44 @@
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.Input;
using DevHome.Common.Extensions;
using DevHome.Contracts.Services;
using DevHome.Dashboard.Helpers;
using DevHome.Dashboard.Services;
using DevHome.Dashboard.ViewModels;
using Microsoft.UI.Dispatching;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Automation;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
using Microsoft.UI.Xaml.Shapes;
using Microsoft.Windows.Widgets.Hosts;
using WinUIEx;

namespace DevHome.Dashboard.Views;

public sealed partial class AddWidgetDialog : ContentDialog
{
private WidgetDefinition _selectedWidget;
private static DispatcherQueue _dispatcher;

public WidgetDefinition AddedWidget { get; private set; }

public AddWidgetViewModel ViewModel { get; set; }

private readonly IWidgetHostingService _hostingService;
private readonly IWidgetIconService _widgetIconService;
private readonly WindowEx _windowEx;

public AddWidgetDialog(
DispatcherQueue dispatcher,
ElementTheme theme)
public AddWidgetDialog()
{
ViewModel = Application.Current.GetService<AddWidgetViewModel>();
_hostingService = Application.Current.GetService<IWidgetHostingService>();
_widgetIconService = Application.Current.GetService<IWidgetIconService>();

this.InitializeComponent();

_dispatcher = dispatcher;
_windowEx = Application.Current.GetService<WindowEx>();

// Strange behavior: just setting the requested theme when we new-up the dialog results in
// the wrong theme's resources being used. Setting RequestedTheme here fixes the problem.
RequestedTheme = theme;
RequestedTheme = Application.Current.GetService<IThemeSelectorService>().Theme;
}

[RelayCommand]
Expand Down Expand Up @@ -225,14 +222,31 @@ private async void AddWidgetNavigationView_SelectionChanged(
if (selectedTag as WidgetDefinition is WidgetDefinition selectedWidgetDefinition)
{
_selectedWidget = selectedWidgetDefinition;
await ViewModel.SetWidgetDefinition(selectedWidgetDefinition, ActualTheme);
await ViewModel.SetWidgetDefinition(selectedWidgetDefinition);
}
else if (selectedTag as WidgetProviderDefinition is not null)
{
ViewModel.Clear();
}
}

[RelayCommand]
private async Task UpdateThemeAsync()
{
// Update the icons for each available widget listed.
foreach (var providerItem in AddWidgetNavigationView.MenuItems.OfType<NavigationViewItem>())
{
foreach (var widgetItem in providerItem.MenuItems.OfType<NavigationViewItem>())
{
if (widgetItem.Tag is WidgetDefinition widgetDefinition)
{
var image = await _widgetIconService.GetWidgetIconForThemeAsync(widgetDefinition, ActualTheme);
widgetItem.Content = BuildNavItem(image, widgetDefinition.DisplayTitle);
}
}
}
}

[RelayCommand]
private void PinButtonClick()
{
Expand Down Expand Up @@ -266,7 +280,7 @@ private void WidgetCatalog_WidgetDefinitionDeleted(WidgetCatalog sender, WidgetD
{
var deletedDefinitionId = args.DefinitionId;

_dispatcher.TryEnqueue(() =>
_windowEx.DispatcherQueue.TryEnqueue(() =>
{
// If we currently have the deleted widget open, un-select it.
if (_selectedWidget is not null &&
Expand All @@ -279,9 +293,9 @@ private void WidgetCatalog_WidgetDefinitionDeleted(WidgetCatalog sender, WidgetD

// Remove the deleted WidgetDefinition from the list of available widgets.
var menuItems = AddWidgetNavigationView.MenuItems;
foreach (var providerItem in menuItems.Cast<NavigationViewItem>())
foreach (var providerItem in menuItems.OfType<NavigationViewItem>())
{
foreach (var widgetItem in providerItem.MenuItems.Cast<NavigationViewItem>())
foreach (var widgetItem in providerItem.MenuItems.OfType<NavigationViewItem>())
{
if (widgetItem.Tag is WidgetDefinition tagDefinition)
{
Expand All @@ -301,6 +315,8 @@ private void WidgetCatalog_WidgetDefinitionDeleted(WidgetCatalog sender, WidgetD
Log.Logger()?.ReportError("AddWidgetDialog", $"WidgetCatalog_WidgetDefinitionDeleted found no available widgets.");
}
}

return;
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -359,11 +359,10 @@ public async Task GoToWidgetsInStoreAsync()
[RelayCommand]
public async Task AddWidgetClickAsync()
{
var dialog = new AddWidgetDialog(_dispatcher, ActualTheme)
var dialog = new AddWidgetDialog()
{
// XamlRoot must be set in the case of a ContentDialog running in a Desktop app.
XamlRoot = this.XamlRoot,
RequestedTheme = this.ActualTheme,
};

_ = await dialog.ShowAsync();
Expand Down
Loading