From d1e51f94e5f84448fce734422396dffa92815e82 Mon Sep 17 00:00:00 2001 From: Kristen Schau <47155823+krschau@users.noreply.github.com> Date: Mon, 16 Sep 2024 11:32:26 -0400 Subject: [PATCH 1/3] Handle FileNotFoundException for widget icons --- .../Services/IWidgetIconService.cs | 3 -- .../Services/WidgetIconService.cs | 17 +++++++-- .../Views/AddWidgetDialog.xaml.cs | 36 ++++++++----------- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/tools/Dashboard/DevHome.Dashboard/Services/IWidgetIconService.cs b/tools/Dashboard/DevHome.Dashboard/Services/IWidgetIconService.cs index 5a0506fc1f..3ffba415e2 100644 --- a/tools/Dashboard/DevHome.Dashboard/Services/IWidgetIconService.cs +++ b/tools/Dashboard/DevHome.Dashboard/Services/IWidgetIconService.cs @@ -5,7 +5,6 @@ using DevHome.Dashboard.ComSafeWidgetObjects; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Media; -using Microsoft.UI.Xaml.Media.Imaging; namespace DevHome.Dashboard.Services; @@ -13,7 +12,5 @@ public interface IWidgetIconService { public void RemoveIconsFromCache(string definitionId); - public Task GetIconFromCacheAsync(ComSafeWidgetDefinition widgetDefinition, ElementTheme theme); - public Task GetBrushForWidgetIconAsync(ComSafeWidgetDefinition widgetDefinition, ElementTheme theme); } diff --git a/tools/Dashboard/DevHome.Dashboard/Services/WidgetIconService.cs b/tools/Dashboard/DevHome.Dashboard/Services/WidgetIconService.cs index 25005da753..3814ed10b7 100644 --- a/tools/Dashboard/DevHome.Dashboard/Services/WidgetIconService.cs +++ b/tools/Dashboard/DevHome.Dashboard/Services/WidgetIconService.cs @@ -38,7 +38,7 @@ public void RemoveIconsFromCache(string definitionId) _widgetDarkIconCache.TryRemove(definitionId, out _); } - public async Task GetIconFromCacheAsync(ComSafeWidgetDefinition widgetDefinition, ElementTheme theme) + private async Task GetIconFromCacheAsync(ComSafeWidgetDefinition widgetDefinition, ElementTheme theme) { var widgetDefinitionId = widgetDefinition.Id; BitmapImage bitmapImage; @@ -75,11 +75,24 @@ public async Task GetIconFromCacheAsync(ComSafeWidgetDefinition wid public async Task GetBrushForWidgetIconAsync(ComSafeWidgetDefinition widgetDefinition, ElementTheme theme) { - var image = await GetIconFromCacheAsync(widgetDefinition, theme); + var image = new BitmapImage(); + try + { + image = await GetIconFromCacheAsync(widgetDefinition, theme); + } + catch (System.IO.FileNotFoundException fileNotFoundEx) + { + _log.Warning(fileNotFoundEx, $"Widget icon missing for widget definition {widgetDefinition.DisplayTitle}"); + } + catch (Exception ex) + { + _log.Error(ex, $"Failed to get widget icon for widget definition {widgetDefinition.DisplayTitle}"); + } var brush = new ImageBrush { ImageSource = image, + Stretch = Stretch.Uniform, }; return brush; diff --git a/tools/Dashboard/DevHome.Dashboard/Views/AddWidgetDialog.xaml.cs b/tools/Dashboard/DevHome.Dashboard/Views/AddWidgetDialog.xaml.cs index a45b058922..cc595cf64f 100644 --- a/tools/Dashboard/DevHome.Dashboard/Views/AddWidgetDialog.xaml.cs +++ b/tools/Dashboard/DevHome.Dashboard/Views/AddWidgetDialog.xaml.cs @@ -150,11 +150,10 @@ private async Task FillAvailableWidgetsAsync() private async Task BuildWidgetNavItem(ComSafeWidgetDefinition widgetDefinition) { - var image = await _widgetIconService.GetIconFromCacheAsync(widgetDefinition, ActualTheme); - return BuildNavItem(image, widgetDefinition.DisplayTitle); + return await BuildNavItem(widgetDefinition); } - private Grid BuildNavItem(BitmapImage image, string text) + private async Task BuildNavItem(ComSafeWidgetDefinition widgetDefinition) { var itemContent = new Grid { @@ -165,32 +164,26 @@ private Grid BuildNavItem(BitmapImage image, string text) }, }; - if (image is not null) + var imageBrush = await _widgetIconService.GetBrushForWidgetIconAsync(widgetDefinition, ActualTheme); + + var itemSquare = new Rectangle() { - var itemSquare = new Rectangle() - { - Width = 16, - Height = 16, - Margin = new Thickness(0, 0, 8, 0), - Fill = new ImageBrush - { - ImageSource = image, - Stretch = Stretch.Uniform, - }, - }; - Grid.SetColumn(itemSquare, 0); + Width = 16, + Height = 16, + Margin = new Thickness(0, 0, 8, 0), + Fill = imageBrush, + }; - itemContent.Children.Add(itemSquare); - } + Grid.SetColumn(itemSquare, 0); + itemContent.Children.Add(itemSquare); var itemText = new TextBlock() { - Text = text, + Text = widgetDefinition.DisplayTitle, TextWrapping = TextWrapping.Wrap, VerticalAlignment = VerticalAlignment.Center, }; Grid.SetColumn(itemText, 1); - itemContent.Children.Add(itemText); return itemContent; @@ -272,8 +265,7 @@ private async Task UpdateThemeAsync() { if (widgetItem.Tag is ComSafeWidgetDefinition widgetDefinition) { - var image = await _widgetIconService.GetIconFromCacheAsync(widgetDefinition, ActualTheme); - widgetItem.Content = BuildNavItem(image, widgetDefinition.DisplayTitle); + widgetItem.Content = await BuildNavItem(widgetDefinition); } } } From 635e12a00ad07319b462ff90bc24763721352c89 Mon Sep 17 00:00:00 2001 From: Kristen Schau <47155823+krschau@users.noreply.github.com> Date: Mon, 16 Sep 2024 11:39:06 -0400 Subject: [PATCH 2/3] Handle FileNotFoundException for widget screenshots --- .../Services/IWidgetScreenshotService.cs | 4 +-- .../Services/WidgetScreenshotService.cs | 30 ++++++++++++++++++- .../ViewModels/AddWidgetViewModel.cs | 12 ++------ 3 files changed, 33 insertions(+), 13 deletions(-) diff --git a/tools/Dashboard/DevHome.Dashboard/Services/IWidgetScreenshotService.cs b/tools/Dashboard/DevHome.Dashboard/Services/IWidgetScreenshotService.cs index 0745806081..6dd5fc28d6 100644 --- a/tools/Dashboard/DevHome.Dashboard/Services/IWidgetScreenshotService.cs +++ b/tools/Dashboard/DevHome.Dashboard/Services/IWidgetScreenshotService.cs @@ -4,7 +4,7 @@ using System.Threading.Tasks; using DevHome.Dashboard.ComSafeWidgetObjects; using Microsoft.UI.Xaml; -using Microsoft.UI.Xaml.Media.Imaging; +using Microsoft.UI.Xaml.Media; namespace DevHome.Dashboard.Services; @@ -12,5 +12,5 @@ public interface IWidgetScreenshotService { public void RemoveScreenshotsFromCache(string definitionId); - public Task GetScreenshotFromCacheAsync(ComSafeWidgetDefinition widgetDefinition, ElementTheme actualTheme); + public Task GetBrushForWidgetScreenshotAsync(ComSafeWidgetDefinition widgetDefinition, ElementTheme theme); } diff --git a/tools/Dashboard/DevHome.Dashboard/Services/WidgetScreenshotService.cs b/tools/Dashboard/DevHome.Dashboard/Services/WidgetScreenshotService.cs index ccb6a19e5b..8b1c3afe2f 100644 --- a/tools/Dashboard/DevHome.Dashboard/Services/WidgetScreenshotService.cs +++ b/tools/Dashboard/DevHome.Dashboard/Services/WidgetScreenshotService.cs @@ -9,14 +9,18 @@ using DevHome.Dashboard.ComSafeWidgetObjects; using Microsoft.UI.Dispatching; using Microsoft.UI.Xaml; +using Microsoft.UI.Xaml.Media; using Microsoft.UI.Xaml.Media.Imaging; using Microsoft.Windows.Widgets.Hosts; +using Serilog; using Windows.Storage.Streams; namespace DevHome.Dashboard.Services; public class WidgetScreenshotService : IWidgetScreenshotService { + private readonly ILogger _log = Log.ForContext("SourceContext", nameof(WidgetScreenshotService)); + private readonly DispatcherQueue _dispatcherQueue; private readonly ConcurrentDictionary _widgetLightScreenshotCache; @@ -36,7 +40,7 @@ public void RemoveScreenshotsFromCache(string definitionId) _widgetDarkScreenshotCache.Remove(definitionId, out _); } - public async Task GetScreenshotFromCacheAsync(ComSafeWidgetDefinition widgetDefinition, ElementTheme actualTheme) + private async Task GetScreenshotFromCacheAsync(ComSafeWidgetDefinition widgetDefinition, ElementTheme actualTheme) { var widgetDefinitionId = widgetDefinition.Id; BitmapImage bitmapImage; @@ -71,6 +75,30 @@ public async Task GetScreenshotFromCacheAsync(ComSafeWidgetDefiniti return bitmapImage; } + public async Task GetBrushForWidgetScreenshotAsync(ComSafeWidgetDefinition widgetDefinition, ElementTheme theme) + { + var image = new BitmapImage(); + try + { + image = await GetScreenshotFromCacheAsync(widgetDefinition, theme); + } + catch (System.IO.FileNotFoundException fileNotFoundEx) + { + _log.Warning(fileNotFoundEx, $"Widget screenshot missing for widget definition {widgetDefinition.DisplayTitle}"); + } + catch (Exception ex) + { + _log.Error(ex, $"Failed to get widget screenshot for widget definition {widgetDefinition.DisplayTitle}"); + } + + var brush = new ImageBrush + { + ImageSource = image, + }; + + return brush; + } + private async Task WidgetScreenshotToBitmapImageAsync(IRandomAccessStreamReference iconStreamRef) { // Return the bitmap image via TaskCompletionSource. Using WCT's EnqueueAsync does not suffice here, since if diff --git a/tools/Dashboard/DevHome.Dashboard/ViewModels/AddWidgetViewModel.cs b/tools/Dashboard/DevHome.Dashboard/ViewModels/AddWidgetViewModel.cs index dafb05165b..4ab38b18df 100644 --- a/tools/Dashboard/DevHome.Dashboard/ViewModels/AddWidgetViewModel.cs +++ b/tools/Dashboard/DevHome.Dashboard/ViewModels/AddWidgetViewModel.cs @@ -41,14 +41,10 @@ public AddWidgetViewModel( public async Task SetWidgetDefinition(ComSafeWidgetDefinition selectedWidgetDefinition) { _selectedWidgetDefinition = selectedWidgetDefinition; - var bitmap = await _widgetScreenshotService.GetScreenshotFromCacheAsync(selectedWidgetDefinition, _themeSelectorService.GetActualTheme()); WidgetDisplayTitle = selectedWidgetDefinition.DisplayTitle; WidgetProviderDisplayTitle = selectedWidgetDefinition.ProviderDefinitionDisplayName; - WidgetScreenshot = new ImageBrush - { - ImageSource = bitmap, - }; + WidgetScreenshot = await _widgetScreenshotService.GetBrushForWidgetScreenshotAsync(selectedWidgetDefinition, _themeSelectorService.GetActualTheme()); PinButtonVisibility = true; } @@ -68,11 +64,7 @@ private async Task UpdateThemeAsync() { // Update the preview image for the selected widget. var theme = _themeSelectorService.GetActualTheme(); - var bitmap = await _widgetScreenshotService.GetScreenshotFromCacheAsync(_selectedWidgetDefinition, theme); - WidgetScreenshot = new ImageBrush - { - ImageSource = bitmap, - }; + WidgetScreenshot = await _widgetScreenshotService.GetBrushForWidgetScreenshotAsync(_selectedWidgetDefinition, theme); } } } From c5f6459c8ad736a29a3a8f13ca53b6031916be56 Mon Sep 17 00:00:00 2001 From: Kristen Schau <47155823+krschau@users.noreply.github.com> Date: Wed, 18 Sep 2024 10:26:42 -0400 Subject: [PATCH 3/3] Add 'Async' to method names --- .../DevHome.Dashboard/Views/AddWidgetDialog.xaml.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tools/Dashboard/DevHome.Dashboard/Views/AddWidgetDialog.xaml.cs b/tools/Dashboard/DevHome.Dashboard/Views/AddWidgetDialog.xaml.cs index cc595cf64f..c40c7b45ce 100644 --- a/tools/Dashboard/DevHome.Dashboard/Views/AddWidgetDialog.xaml.cs +++ b/tools/Dashboard/DevHome.Dashboard/Views/AddWidgetDialog.xaml.cs @@ -117,7 +117,7 @@ private async Task FillAvailableWidgetsAsync() { if (widgetDef.ProviderDefinitionId.Equals(providerDef.Id, StringComparison.Ordinal)) { - var subItemContent = await BuildWidgetNavItem(widgetDef); + var subItemContent = await BuildWidgetNavItemAsync(widgetDef); var enable = !IsSingleInstanceAndAlreadyPinned(widgetDef, [.. comSafeCurrentlyPinnedWidgets]); var subItem = new NavigationViewItem { @@ -148,12 +148,12 @@ private async Task FillAvailableWidgetsAsync() } } - private async Task BuildWidgetNavItem(ComSafeWidgetDefinition widgetDefinition) + private async Task BuildWidgetNavItemAsync(ComSafeWidgetDefinition widgetDefinition) { - return await BuildNavItem(widgetDefinition); + return await BuildNavItemAsync(widgetDefinition); } - private async Task BuildNavItem(ComSafeWidgetDefinition widgetDefinition) + private async Task BuildNavItemAsync(ComSafeWidgetDefinition widgetDefinition) { var itemContent = new Grid { @@ -265,7 +265,7 @@ private async Task UpdateThemeAsync() { if (widgetItem.Tag is ComSafeWidgetDefinition widgetDefinition) { - widgetItem.Content = await BuildNavItem(widgetDefinition); + widgetItem.Content = await BuildNavItemAsync(widgetDefinition); } } }