/ src / modules / cmdpal / Microsoft.CmdPal.UI / Settings / AppearancePage.xaml.cs
AppearancePage.xaml.cs
 1  // Copyright (c) Microsoft Corporation
 2  // The Microsoft Corporation licenses this file to you under the MIT license.
 3  // See the LICENSE file in the project root for more information.
 4  
 5  using System.Diagnostics;
 6  using ManagedCommon;
 7  using Microsoft.CmdPal.UI.ViewModels;
 8  using Microsoft.CmdPal.UI.ViewModels.Services;
 9  using Microsoft.Extensions.DependencyInjection;
10  using Microsoft.UI;
11  using Microsoft.UI.Xaml;
12  using Microsoft.UI.Xaml.Controls;
13  using Microsoft.UI.Xaml.Documents;
14  using Microsoft.Windows.Storage.Pickers;
15  
16  namespace Microsoft.CmdPal.UI.Settings;
17  
18  /// <summary>
19  /// An empty page that can be used on its own or navigated to within a Frame.
20  /// </summary>
21  public sealed partial class AppearancePage : Page
22  {
23      private readonly TaskScheduler _mainTaskScheduler = TaskScheduler.FromCurrentSynchronizationContext();
24  
25      internal SettingsViewModel ViewModel { get; }
26  
27      public AppearancePage()
28      {
29          InitializeComponent();
30  
31          var settings = App.Current.Services.GetService<SettingsModel>()!;
32          var themeService = App.Current.Services.GetRequiredService<IThemeService>();
33          var topLevelCommandManager = App.Current.Services.GetService<TopLevelCommandManager>()!;
34          ViewModel = new SettingsViewModel(settings, topLevelCommandManager, _mainTaskScheduler, themeService);
35      }
36  
37      private async void PickBackgroundImage_Click(object sender, RoutedEventArgs e)
38      {
39          try
40          {
41              if (XamlRoot?.ContentIslandEnvironment is null)
42              {
43                  return;
44              }
45  
46              var windowId = XamlRoot?.ContentIslandEnvironment?.AppWindowId ?? new WindowId(0);
47  
48              var picker = new FileOpenPicker(windowId)
49              {
50                  CommitButtonText = ViewModels.Properties.Resources.builtin_settings_appearance_pick_background_image_title!,
51                  SuggestedStartLocation = PickerLocationId.PicturesLibrary,
52                  ViewMode = PickerViewMode.Thumbnail,
53              };
54  
55              string[] extensions = [".png", ".bmp", ".jpg", ".jpeg", ".jfif", ".gif", ".tiff", ".tif", ".webp", ".jxr"];
56              foreach (var ext in extensions)
57              {
58                  picker.FileTypeFilter!.Add(ext);
59              }
60  
61              var file = await picker.PickSingleFileAsync()!;
62              if (file != null)
63              {
64                  ViewModel.Appearance.BackgroundImagePath = file.Path ?? string.Empty;
65              }
66          }
67          catch (Exception ex)
68          {
69              Logger.LogError("Failed to pick background image file", ex);
70          }
71      }
72  
73      private void OpenWindowsColorsSettings_Click(Hyperlink sender, HyperlinkClickEventArgs args)
74      {
75          // LOAD BEARING (or BEAR LOADING?): Process.Start with UseShellExecute inside a XAML input event can trigger WinUI reentrancy
76          // and cause FailFast crashes. Task.Run moves the call off the UI thread to prevent hard process termination.
77          Task.Run(() =>
78          {
79              try
80              {
81                  _ = Process.Start(new ProcessStartInfo("ms-settings:colors") { UseShellExecute = true });
82              }
83              catch (Exception ex)
84              {
85                  Logger.LogError("Failed to open Windows Settings", ex);
86              }
87          });
88      }
89  }