Skip to content

Commit

Permalink
Pin default widgets (#2233)
Browse files Browse the repository at this point in the history
* pin default widgets on first run if there are no other widgets pinned

* Async
  • Loading branch information
krschau committed Feb 9, 2024
1 parent 841408e commit 8c3fee8
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 5 deletions.
2 changes: 2 additions & 0 deletions common/Helpers/WellKnownSettingsKeys.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,6 @@ namespace DevHome.Common.Helpers;
public class WellKnownSettingsKeys
{
public const string IsNotFirstRun = "IsNotFirstRun";

public const string IsNotFirstDashboardRun = "IsNotFirstDashboardRun";
}
17 changes: 17 additions & 0 deletions tools/Dashboard/DevHome.Dashboard/Helpers/WidgetHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,23 @@ internal sealed class WidgetHelpers
public const string WidgetServiceStorePackageId = "9N3RK8ZV2ZR8";
public const string WidgetServicePackageFamilyName = "Microsoft.WidgetsPlatformRuntime_8wekyb3d8bbwe";

public static readonly string[] DefaultWidgetDefinitionIds =
{
#if CANARY_BUILD
"Microsoft.Windows.DevHome.Canary_8wekyb3d8bbwe!App!!CoreWidgetProvider!!System_CPUUsage",
"Microsoft.Windows.DevHome.Canary_8wekyb3d8bbwe!App!!CoreWidgetProvider!!System_GPUUsage",
"Microsoft.Windows.DevHome.Canary_8wekyb3d8bbwe!App!!CoreWidgetProvider!!System_NetworkUsage",
#elif STABLE_BUILD
"Microsoft.Windows.DevHome_8wekyb3d8bbwe!App!!CoreWidgetProvider!!System_CPUUsage",
"Microsoft.Windows.DevHome_8wekyb3d8bbwe!App!!CoreWidgetProvider!!System_GPUUsage",
"Microsoft.Windows.DevHome_8wekyb3d8bbwe!App!!CoreWidgetProvider!!System_NetworkUsage",
#else
"Microsoft.Windows.DevHome.Dev_8wekyb3d8bbwe!App!!CoreWidgetProvider!!System_CPUUsage",
"Microsoft.Windows.DevHome.Dev_8wekyb3d8bbwe!App!!CoreWidgetProvider!!System_GPUUsage",
"Microsoft.Windows.DevHome.Dev_8wekyb3d8bbwe!App!!CoreWidgetProvider!!System_NetworkUsage",
#endif
};

public const string DevHomeHostName = "DevHome";

private const double WidgetPxHeightSmall = 146;
Expand Down
89 changes: 84 additions & 5 deletions tools/Dashboard/DevHome.Dashboard/Views/DashboardView.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.Input;
using DevHome.Common;
using DevHome.Common.Contracts;
using DevHome.Common.Extensions;
using DevHome.Common.Helpers;
using DevHome.Dashboard.Controls;
using DevHome.Dashboard.Helpers;
using DevHome.Dashboard.Services;
Expand All @@ -21,6 +23,7 @@
using Microsoft.Windows.Widgets;
using Microsoft.Windows.Widgets.Hosts;
using Windows.System;
using Log = DevHome.Dashboard.Helpers.Log;

namespace DevHome.Dashboard.Views;

Expand All @@ -37,6 +40,7 @@ public partial class DashboardView : ToolPage
public static ObservableCollection<WidgetViewModel> PinnedWidgets { get; set; }

private static Microsoft.UI.Dispatching.DispatcherQueue _dispatcher;
private readonly ILocalSettingsService _localSettingsService;

private const string DraggedWidget = "DraggedWidget";
private const string DraggedIndex = "DraggedIndex";
Expand All @@ -52,6 +56,7 @@ public DashboardView()
PinnedWidgets = new ObservableCollection<WidgetViewModel>();

_dispatcher = Microsoft.UI.Dispatching.DispatcherQueue.GetForCurrentThread();
_localSettingsService = Application.Current.GetService<ILocalSettingsService>();

ActualThemeChanged += OnActualThemeChanged;

Expand Down Expand Up @@ -119,7 +124,13 @@ private async Task InitializeDashboard()
// Cache the widget icons before we display the widgets, since we include the icons in the widgets.
await ViewModel.WidgetIconService.CacheAllWidgetIconsAsync();

await RestorePinnedWidgetsAsync();
var isFirstDashboardRun = !(await _localSettingsService.ReadSettingAsync<bool>(WellKnownSettingsKeys.IsNotFirstDashboardRun));
if (isFirstDashboardRun)
{
await Application.Current.GetService<ILocalSettingsService>().SaveSettingAsync(WellKnownSettingsKeys.IsNotFirstDashboardRun, true);
}

await InitializePinnedWidgetListAsync(isFirstDashboardRun);
}
else
{
Expand All @@ -141,7 +152,22 @@ private async Task InitializeDashboard()
ViewModel.IsLoading = false;
}

private async Task RestorePinnedWidgetsAsync()
private async Task InitializePinnedWidgetListAsync(bool isFirstDashboardRun)
{
var hostWidgets = await GetPreviouslyPinnedWidgets();

if ((hostWidgets == null || hostWidgets.Length == 0) && isFirstDashboardRun)
{
// If it's the first time the Dashboard has been displayed and we have no other widgets pinned to a
// different version of Dev Home, pin some default widgets.
await PinDefaultWidgetsAsync();
return;
}

await RestorePinnedWidgetsAsync(hostWidgets);
}

private async Task<Widget[]> GetPreviouslyPinnedWidgets()
{
Log.Logger()?.ReportInfo("DashboardView", "Get widgets for current host");
var widgetHost = await ViewModel.WidgetHostingService.GetWidgetHostAsync();
Expand All @@ -150,10 +176,16 @@ private async Task RestorePinnedWidgetsAsync()
if (hostWidgets == null)
{
Log.Logger()?.ReportInfo("DashboardView", $"Found 0 widgets for this host");
return;
return null;
}

Log.Logger()?.ReportInfo("DashboardView", $"Found {hostWidgets.Length} widgets for this host");

return hostWidgets;
}

private async Task RestorePinnedWidgetsAsync(Widget[] hostWidgets)
{
var restoredWidgetsWithPosition = new SortedDictionary<int, Widget>();
var restoredWidgetsWithoutPosition = new SortedDictionary<int, Widget>();
var numUnorderedWidgets = 0;
Expand All @@ -172,7 +204,7 @@ private async Task RestorePinnedWidgetsAsync()
{
// If we have a widget with no state, Dev Home does not consider it a valid widget
// and should delete it, rather than letting it run invisibly in the background.
await DeleteAbandonedWidgetAsync(widget, widgetHost);
await DeleteAbandonedWidgetAsync(widget);
continue;
}

Expand Down Expand Up @@ -219,8 +251,10 @@ private async Task RestorePinnedWidgetsAsync()
}
}

private async Task DeleteAbandonedWidgetAsync(Widget widget, WidgetHost widgetHost)
private async Task DeleteAbandonedWidgetAsync(Widget widget)
{
var widgetHost = await ViewModel.WidgetHostingService.GetWidgetHostAsync();

var length = await Task.Run(() => widgetHost!.GetWidgets().Length);
Log.Logger()?.ReportInfo("DashboardView", $"Found abandoned widget, try to delete it...");
Log.Logger()?.ReportInfo("DashboardView", $"Before delete, {length} widgets for this host");
Expand All @@ -240,6 +274,51 @@ private async Task PlaceWidget(KeyValuePair<int, Widget> orderedWidget, int fina
await WidgetHelpers.SetPositionCustomStateAsync(widget, finalPlace);
}

private async Task PinDefaultWidgetsAsync()
{
var catalog = await ViewModel.WidgetHostingService.GetWidgetCatalogAsync();

if (catalog is null)
{
Log.Logger()?.ReportError("AddWidgetDialog", $"Trying to pin default widgets, but WidgetCatalog is null.");
return;
}

var widgetDefinitions = await Task.Run(() => catalog!.GetWidgetDefinitions().OrderBy(x => x.DisplayTitle));
foreach (var widgetDefinition in widgetDefinitions)
{
var id = widgetDefinition.Id;
if (WidgetHelpers.DefaultWidgetDefinitionIds.Contains(id))
{
await PinDefaultWidgetAsync(widgetDefinition);
}
}
}

private async Task PinDefaultWidgetAsync(WidgetDefinition defaultWidgetDefinition)
{
try
{
// Create widget
var widgetHost = await ViewModel.WidgetHostingService.GetWidgetHostAsync();
var size = WidgetHelpers.GetDefaultWidgetSize(defaultWidgetDefinition.GetWidgetCapabilities());
var newWidget = await Task.Run(async () => await widgetHost?.CreateWidgetAsync(defaultWidgetDefinition.Id, size));

// Set custom state on new widget.
var position = PinnedWidgets.Count;
var newCustomState = WidgetHelpers.CreateWidgetCustomState(position);
Log.Logger()?.ReportDebug("DashboardView", $"SetCustomState: {newCustomState}");
await newWidget.SetCustomStateAsync(newCustomState);

// Put new widget on the Dashboard.
await InsertWidgetInPinnedWidgetsAsync(newWidget, size, position);
}
catch (Exception ex)
{
Log.Logger()?.ReportError("AddWidgetDialog", $"PinDefaultWidget failed: ", ex);
}
}

[RelayCommand]
public async Task GoToWidgetsInStoreAsync()
{
Expand Down

0 comments on commit 8c3fee8

Please sign in to comment.