Skip to content

Commit

Permalink
Feature: Added a theming option to display a background image (files-…
Browse files Browse the repository at this point in the history
  • Loading branch information
yaira2 authored May 3, 2024
1 parent b9fa67e commit 10bfa4b
Show file tree
Hide file tree
Showing 7 changed files with 380 additions and 0 deletions.
41 changes: 41 additions & 0 deletions src/Files.App/Services/Settings/AppearanceSettingsService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
// Licensed under the MIT License. See the LICENSE.

using Microsoft.AppCenter.Analytics;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;

namespace Files.App.Services.Settings
{
Expand Down Expand Up @@ -74,6 +76,41 @@ public BackdropMaterialType AppThemeBackdropMaterial
set => Set(value);
}

/// <inheritdoc/>
public string AppThemeBackgroundImageSource
{
get => Get("");
set => Set(value);
}

/// <inheritdoc/>
public Stretch AppThemeBackgroundImageFit
{
get => Get(Stretch.UniformToFill);
set => Set(value);
}

/// <inheritdoc/>
public float AppThemeBackgroundImageOpacity
{
get => Get(1f);
set => Set(value);
}

/// <inheritdoc/>
public VerticalAlignment AppThemeBackgroundImageVerticalAlignment
{
get => Get(VerticalAlignment.Center);
set => Set(value);
}

/// <inheritdoc/>
public HorizontalAlignment AppThemeBackgroundImageHorizontalAlignment
{
get => Get(HorizontalAlignment.Center);
set => Set(value);
}

protected override void RaiseOnSettingChangedEvent(object sender, SettingChangedEventArgs e)
{
switch (e.SettingName)
Expand All @@ -83,6 +120,10 @@ protected override void RaiseOnSettingChangedEvent(object sender, SettingChanged
case nameof(AppThemeSidebarBackgroundColor):
case nameof(AppThemeFileAreaBackgroundColor):
case nameof(AppThemeBackdropMaterial):
case nameof(AppThemeBackgroundImageFit):
case nameof(AppThemeBackgroundImageOpacity):
case nameof(AppThemeBackgroundImageVerticalAlignment):
case nameof(AppThemeBackgroundImageHorizontalAlignment):
Analytics.TrackEvent($"Set {e.SettingName} to {e.NewValue}");
break;
}
Expand Down
28 changes: 28 additions & 0 deletions src/Files.App/Services/Settings/IAppearanceSettingsService.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// Copyright (c) 2024 Files Community
// Licensed under the MIT License. See the LICENSE.

using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;

namespace Files.App.Services.Settings
{
public interface IAppearanceSettingsService : IBaseSettingsService, INotifyPropertyChanged
Expand Down Expand Up @@ -53,5 +56,30 @@ public interface IAppearanceSettingsService : IBaseSettingsService, INotifyPrope
/// Gets or sets a value for the theme system backdrop.
/// </summary>
BackdropMaterialType AppThemeBackdropMaterial { get; set; }

/// <summary>
/// Gets or sets a value for the app background image source
/// </summary>
string AppThemeBackgroundImageSource { get; set; }

/// <summary>
/// Gets or sets a value for the app background image fit.
/// </summary>
Stretch AppThemeBackgroundImageFit { get; set; }

/// <summary>
/// Gets or sets a value for the app background image opacity.
/// </summary>
float AppThemeBackgroundImageOpacity { get; set; }

/// <summary>
/// Gets or sets a value for the app background image Vertical Alignment.
/// </summary>
VerticalAlignment AppThemeBackgroundImageVerticalAlignment { get; set; }

/// <summary>
/// Gets or sets a value for the app background image Horizontal Alignment.
/// </summary>
HorizontalAlignment AppThemeBackgroundImageHorizontalAlignment { get; set; }
}
}
51 changes: 51 additions & 0 deletions src/Files.App/Strings/en-US/Resources.resw
Original file line number Diff line number Diff line change
Expand Up @@ -3737,4 +3737,55 @@
<data name="AdaptiveLayoutDisabledNotification" xml:space="preserve">
<value>Adaptive layout is not available when preferences are synced, the default layout has been changed to Details.</value>
</data>
<data name="BackgroundImage" xml:space="preserve">
<value>Background image</value>
</data>
<data name="Bottom" xml:space="preserve">
<value>Bottom</value>
<comment>Image alignment type</comment>
</data>
<data name="Center" xml:space="preserve">
<value>Center</value>
<comment>Image alignment type</comment>
</data>
<data name="Fill" xml:space="preserve">
<value>Fill</value>
<comment>Image stretch type</comment>
</data>
<data name="HorizontalAlignment" xml:space="preserve">
<value>Horizontal alignment</value>
</data>
<data name="ImageFit" xml:space="preserve">
<value>Image fit</value>
</data>
<data name="Left" xml:space="preserve">
<value>Left</value>
<comment>Image alignment type</comment>
</data>
<data name="Opacity" xml:space="preserve">
<value>Opacity</value>
</data>
<data name="Right" xml:space="preserve">
<value>Right</value>
<comment>Image alignment type</comment>
</data>
<data name="Stretch" xml:space="preserve">
<value>Stretch</value>
<comment>Image alignment type</comment>
</data>
<data name="Top" xml:space="preserve">
<value>Top</value>
<comment>Image alignment type</comment>
</data>
<data name="Uniform" xml:space="preserve">
<value>Uniform</value>
<comment>Image stretch type</comment>
</data>
<data name="UniformToFill" xml:space="preserve">
<value>Uniform to fill</value>
<comment>Image stretch type</comment>
</data>
<data name="VerticalAlignment" xml:space="preserve">
<value>Vertical alignment</value>
</data>
</root>
43 changes: 43 additions & 0 deletions src/Files.App/ViewModels/MainPageViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
// Copyright (c) 2024 Files Community
// Licensed under the MIT License. See the LICENSE.

using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Media.Imaging;
using Microsoft.UI.Xaml.Navigation;
using System.Windows.Input;
using Windows.System;
Expand Down Expand Up @@ -57,6 +60,24 @@ public bool ShouldPreviewPaneBeDisplayed
set => SetProperty(ref shouldPreviewPaneBeDisplayed, value);
}

public Stretch AppThemeBackgroundImageFit
=> AppearanceSettingsService.AppThemeBackgroundImageFit;

public float AppThemeBackgroundImageOpacity
=> AppearanceSettingsService.AppThemeBackgroundImageOpacity;

public ImageSource? AppThemeBackgroundImageSource =>
string.IsNullOrEmpty(AppearanceSettingsService.AppThemeBackgroundImageSource)
? null
: new BitmapImage(new Uri(AppearanceSettingsService.AppThemeBackgroundImageSource, UriKind.RelativeOrAbsolute));

public VerticalAlignment AppThemeBackgroundImageVerticalAlignment
=> AppearanceSettingsService.AppThemeBackgroundImageVerticalAlignment;

public HorizontalAlignment AppThemeBackgroundImageHorizontalAlignment
=> AppearanceSettingsService.AppThemeBackgroundImageHorizontalAlignment;


// Commands

public ICommand NavigateToNumberedTabKeyboardAcceleratorCommand { get; }
Expand All @@ -66,6 +87,28 @@ public bool ShouldPreviewPaneBeDisplayed
public MainPageViewModel()
{
NavigateToNumberedTabKeyboardAcceleratorCommand = new RelayCommand<KeyboardAcceleratorInvokedEventArgs>(ExecuteNavigateToNumberedTabKeyboardAcceleratorCommand);

AppearanceSettingsService.PropertyChanged += (s, e) =>
{
switch (e.PropertyName)
{
case nameof(AppearanceSettingsService.AppThemeBackgroundImageSource):
OnPropertyChanged(nameof(AppThemeBackgroundImageSource));
break;
case nameof(AppearanceSettingsService.AppThemeBackgroundImageOpacity):
OnPropertyChanged(nameof(AppThemeBackgroundImageOpacity));
break;
case nameof(AppearanceSettingsService.AppThemeBackgroundImageFit):
OnPropertyChanged(nameof(AppThemeBackgroundImageFit));
break;
case nameof(AppearanceSettingsService.AppThemeBackgroundImageVerticalAlignment):
OnPropertyChanged(nameof(AppThemeBackgroundImageVerticalAlignment));
break;
case nameof(AppearanceSettingsService.AppThemeBackgroundImageHorizontalAlignment):
OnPropertyChanged(nameof(AppThemeBackgroundImageHorizontalAlignment));
break;
}
};
}

// Methods
Expand Down
137 changes: 137 additions & 0 deletions src/Files.App/ViewModels/Settings/AppearanceViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
// Licensed under the MIT License. See the LICENSE.

using CommunityToolkit.WinUI.Helpers;
using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media;
using System.Windows.Input;
using Windows.Storage.Pickers;
using Windows.UI.WindowManagement;

namespace Files.App.ViewModels.Settings
{
Expand All @@ -15,8 +20,17 @@ public sealed class AppearanceViewModel : ObservableObject
public List<string> Themes { get; private set; }
public Dictionary<BackdropMaterialType, string> BackdropMaterialTypes { get; private set; } = [];

public Dictionary<Stretch, string> ImageStretchTypes { get; private set; } = [];

public Dictionary<VerticalAlignment, string> ImageVerticalAlignmentTypes { get; private set; } = [];

public Dictionary<HorizontalAlignment, string> ImageHorizontalAlignmentTypes { get; private set; } = [];

public ObservableCollection<AppThemeResourceItem> AppThemeResources { get; }

public ICommand SelectImageCommand { get; }
public ICommand RemoveImageCommand { get; }

public AppearanceViewModel(IUserSettingsService userSettingsService, IResourcesService resourcesService)
{
UserSettingsService = userSettingsService;
Expand All @@ -42,7 +56,64 @@ public AppearanceViewModel(IUserSettingsService userSettingsService, IResourcesS

AppThemeResources = AppThemeResourceFactory.AppThemeResources;


// Background image fit options
ImageStretchTypes.Add(Stretch.None, "None".GetLocalizedResource());
ImageStretchTypes.Add(Stretch.Fill, "Fill".GetLocalizedResource());
ImageStretchTypes.Add(Stretch.Uniform, "Uniform".GetLocalizedResource());
ImageStretchTypes.Add(Stretch.UniformToFill, "UniformToFill".GetLocalizedResource());
SelectedImageStretchType = ImageStretchTypes[UserSettingsService.AppearanceSettingsService.AppThemeBackgroundImageFit];

// Background image allignment options

// VerticalAlignment
ImageVerticalAlignmentTypes.Add(VerticalAlignment.Top, "Top".GetLocalizedResource());
ImageVerticalAlignmentTypes.Add(VerticalAlignment.Center, "Center".GetLocalizedResource());
ImageVerticalAlignmentTypes.Add(VerticalAlignment.Bottom, "Bottom".GetLocalizedResource());
ImageVerticalAlignmentTypes.Add(VerticalAlignment.Stretch, "Stretch".GetLocalizedResource());
SelectedImageVerticalAlignmentType = ImageVerticalAlignmentTypes[UserSettingsService.AppearanceSettingsService.AppThemeBackgroundImageVerticalAlignment];

// HorizontalAlignment
ImageHorizontalAlignmentTypes.Add(HorizontalAlignment.Left, "Top".GetLocalizedResource());
ImageHorizontalAlignmentTypes.Add(HorizontalAlignment.Center, "Center".GetLocalizedResource());
ImageHorizontalAlignmentTypes.Add(HorizontalAlignment.Right, "Bottom".GetLocalizedResource());
ImageHorizontalAlignmentTypes.Add(HorizontalAlignment.Stretch, "Stretch".GetLocalizedResource());
SelectedImageHorizontalAlignmentType = ImageHorizontalAlignmentTypes[UserSettingsService.AppearanceSettingsService.AppThemeBackgroundImageHorizontalAlignment];

UpdateSelectedResource();

SelectImageCommand = new AsyncRelayCommand(SelectBackgroundImage);
RemoveImageCommand = new RelayCommand(RemoveBackgroundImage);
}

/// <summary>
/// Opens a file picker to select a background image
/// </summary>
private async Task SelectBackgroundImage()
{
var filePicker = new FileOpenPicker
{
ViewMode = PickerViewMode.Thumbnail,
SuggestedStartLocation = PickerLocationId.PicturesLibrary,
FileTypeFilter = { ".jpg", ".jpeg", ".png", ".bmp", ".gif", ".webp" }
};

// WINUI3: Create and initialize new window
var parentWindowId = MainWindow.Instance.AppWindow.Id;
var handle = Microsoft.UI.Win32Interop.GetWindowFromWindowId(parentWindowId);
WinRT.Interop.InitializeWithWindow.Initialize(filePicker, handle);

var file = await filePicker.PickSingleFileAsync();
if (file is not null)
AppThemeBackgroundImageSource = file.Path;
}

/// <summary>
/// Clears the current background image
/// </summary>
private void RemoveBackgroundImage()
{
AppThemeBackgroundImageSource = string.Empty;
}

/// <summary>
Expand Down Expand Up @@ -143,5 +214,71 @@ public string SelectedBackdropMaterial
}
}

public string AppThemeBackgroundImageSource
{
get => UserSettingsService.AppearanceSettingsService.AppThemeBackgroundImageSource;
set
{
if (value != UserSettingsService.AppearanceSettingsService.AppThemeBackgroundImageSource)
{
UserSettingsService.AppearanceSettingsService.AppThemeBackgroundImageSource = value;

OnPropertyChanged();
}
}
}

private string selectedImageStretchType;
public string SelectedImageStretchType
{
get => selectedImageStretchType;
set
{
if (SetProperty(ref selectedImageStretchType, value))
{
UserSettingsService.AppearanceSettingsService.AppThemeBackgroundImageFit = ImageStretchTypes.First(e => e.Value == value).Key;
}
}
}

public float AppThemeBackgroundImageOpacity
{
get => UserSettingsService.AppearanceSettingsService.AppThemeBackgroundImageOpacity;
set
{
if (value != UserSettingsService.AppearanceSettingsService.AppThemeBackgroundImageOpacity)
{
UserSettingsService.AppearanceSettingsService.AppThemeBackgroundImageOpacity = value;

OnPropertyChanged();
}
}
}

private string selectedImageVerticalAlignmentType;
public string SelectedImageVerticalAlignmentType
{
get => selectedImageVerticalAlignmentType;
set
{
if (SetProperty(ref selectedImageVerticalAlignmentType, value))
{
UserSettingsService.AppearanceSettingsService.AppThemeBackgroundImageVerticalAlignment = ImageVerticalAlignmentTypes.First(e => e.Value == value).Key;
}
}
}

private string selectedImageHorizontalAlignmentType;
public string SelectedImageHorizontalAlignmentType
{
get => selectedImageHorizontalAlignmentType;
set
{
if (SetProperty(ref selectedImageHorizontalAlignmentType, value))
{
UserSettingsService.AppearanceSettingsService.AppThemeBackgroundImageHorizontalAlignment = ImageHorizontalAlignmentTypes.First(e => e.Value == value).Key;
}
}
}
}
}
Loading

0 comments on commit 10bfa4b

Please sign in to comment.