[Settings]ImageResizer settings accessibility updates, fixes and refactor (#36903)
* Fix issue with missing Image Resizer unit and fit information in settings description. * Fix accessibility issues on Edit and Remove buttons. Fix various issues and refactor view model and ImageSize. New resources for accessibility text formats. * Fix unit test because of change to new preset width and height. Fix 2 unit tests having incorrect expected/actual orderings. * Post-review update: accessibility strings now formatted within the converter, instead of via format strings; simplified encoder GUID collection declaration and retrieval. * Minor example text fix.
This commit is contained in:
Родитель
b33e0be178
Коммит
438d17302e
|
@ -3,241 +3,119 @@
|
||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
using System.Text.Json.Serialization;
|
using System.Text.Json.Serialization;
|
||||||
|
using Settings.UI.Library.Resources;
|
||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI.Library
|
namespace Microsoft.PowerToys.Settings.UI.Library;
|
||||||
|
|
||||||
|
public partial class ImageSize : INotifyPropertyChanged
|
||||||
{
|
{
|
||||||
public class ImageSize : INotifyPropertyChanged
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
private bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
|
||||||
{
|
{
|
||||||
public ImageSize(int id)
|
bool changed = !EqualityComparer<T>.Default.Equals(field, value);
|
||||||
|
if (changed)
|
||||||
{
|
{
|
||||||
Id = id;
|
field = value;
|
||||||
Name = string.Empty;
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
Fit = ResizeFit.Fit;
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(AccessibleTextHelper)));
|
||||||
Width = 0;
|
|
||||||
Height = 0;
|
|
||||||
Unit = ResizeUnit.Pixel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ImageSize()
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ImageSize(int id = 0, string name = "", ResizeFit fit = ResizeFit.Fit, double width = 0, double height = 0, ResizeUnit unit = ResizeUnit.Pixel)
|
||||||
|
{
|
||||||
|
Id = id;
|
||||||
|
Name = name;
|
||||||
|
Fit = fit;
|
||||||
|
Width = width;
|
||||||
|
Height = height;
|
||||||
|
Unit = unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int _id;
|
||||||
|
private string _name;
|
||||||
|
private ResizeFit _fit;
|
||||||
|
private double _height;
|
||||||
|
private double _width;
|
||||||
|
private ResizeUnit _unit;
|
||||||
|
|
||||||
|
public int Id
|
||||||
|
{
|
||||||
|
get => _id;
|
||||||
|
set => SetProperty(ref _id, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a value indicating whether the <see cref="Height"/> property is used. When false, the
|
||||||
|
/// <see cref="Width"/> property is used to evenly scale the image in both X and Y dimensions.
|
||||||
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
|
public bool IsHeightUsed
|
||||||
|
{
|
||||||
|
// Height is ignored when using percentage scaling where the aspect ratio is maintained
|
||||||
|
// (i.e. non-stretch fits). In all other cases, both Width and Height are needed.
|
||||||
|
get => !(Unit == ResizeUnit.Percent && Fit != ResizeFit.Stretch);
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonPropertyName("name")]
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get => _name;
|
||||||
|
set => SetProperty(ref _name, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonPropertyName("fit")]
|
||||||
|
public ResizeFit Fit
|
||||||
|
{
|
||||||
|
get => _fit;
|
||||||
|
set
|
||||||
{
|
{
|
||||||
Id = 0;
|
if (SetProperty(ref _fit, value))
|
||||||
Name = string.Empty;
|
|
||||||
Fit = ResizeFit.Fit;
|
|
||||||
Width = 0;
|
|
||||||
Height = 0;
|
|
||||||
Unit = ResizeUnit.Pixel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ImageSize(int id, string name, ResizeFit fit, double width, double height, ResizeUnit unit)
|
|
||||||
{
|
|
||||||
Id = id;
|
|
||||||
Name = name;
|
|
||||||
Fit = fit;
|
|
||||||
Width = width;
|
|
||||||
Height = height;
|
|
||||||
Unit = unit;
|
|
||||||
}
|
|
||||||
|
|
||||||
private int _id;
|
|
||||||
private string _name;
|
|
||||||
private ResizeFit _fit;
|
|
||||||
private double _height;
|
|
||||||
private double _width;
|
|
||||||
private ResizeUnit _unit;
|
|
||||||
|
|
||||||
public int Id
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
{
|
||||||
return _id;
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsHeightUsed)));
|
||||||
}
|
}
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_id != value)
|
|
||||||
{
|
|
||||||
_id = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int ExtraBoxOpacity
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (Unit == ResizeUnit.Percent && Fit != ResizeFit.Stretch)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return 100;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool EnableEtraBoxes
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (Unit == ResizeUnit.Percent && Fit != ResizeFit.Stretch)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[JsonPropertyName("name")]
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _name;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_name != value)
|
|
||||||
{
|
|
||||||
_name = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[JsonPropertyName("fit")]
|
|
||||||
public ResizeFit Fit
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _fit;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_fit != value)
|
|
||||||
{
|
|
||||||
_fit = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
OnPropertyChanged(nameof(ExtraBoxOpacity));
|
|
||||||
OnPropertyChanged(nameof(EnableEtraBoxes));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[JsonPropertyName("width")]
|
|
||||||
public double Width
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _width;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
double newWidth = -1;
|
|
||||||
|
|
||||||
if (value < 0 || double.IsNaN(value))
|
|
||||||
{
|
|
||||||
newWidth = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
newWidth = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_width != newWidth)
|
|
||||||
{
|
|
||||||
_width = newWidth;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[JsonPropertyName("height")]
|
|
||||||
public double Height
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _height;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
double newHeight = -1;
|
|
||||||
|
|
||||||
if (value < 0 || double.IsNaN(value))
|
|
||||||
{
|
|
||||||
newHeight = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
newHeight = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_height != newHeight)
|
|
||||||
{
|
|
||||||
_height = newHeight;
|
|
||||||
OnPropertyChanged();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[JsonPropertyName("unit")]
|
|
||||||
public ResizeUnit Unit
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _unit;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_unit != value)
|
|
||||||
{
|
|
||||||
_unit = value;
|
|
||||||
OnPropertyChanged();
|
|
||||||
OnPropertyChanged(nameof(ExtraBoxOpacity));
|
|
||||||
OnPropertyChanged(nameof(EnableEtraBoxes));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
|
||||||
|
|
||||||
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
|
|
||||||
{
|
|
||||||
var handler = PropertyChanged;
|
|
||||||
if (handler != null)
|
|
||||||
{
|
|
||||||
handler(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Update(ImageSize modifiedSize)
|
|
||||||
{
|
|
||||||
ArgumentNullException.ThrowIfNull(modifiedSize);
|
|
||||||
|
|
||||||
Id = modifiedSize.Id;
|
|
||||||
Name = modifiedSize.Name;
|
|
||||||
Fit = modifiedSize.Fit;
|
|
||||||
Width = modifiedSize.Width;
|
|
||||||
Height = modifiedSize.Height;
|
|
||||||
Unit = modifiedSize.Unit;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string ToJsonString()
|
|
||||||
{
|
|
||||||
return JsonSerializer.Serialize(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[JsonPropertyName("width")]
|
||||||
|
public double Width
|
||||||
|
{
|
||||||
|
get => _width;
|
||||||
|
set => SetProperty(ref _width, value < 0 || double.IsNaN(value) ? 0 : value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonPropertyName("height")]
|
||||||
|
public double Height
|
||||||
|
{
|
||||||
|
get => _height;
|
||||||
|
set => SetProperty(ref _height, value < 0 || double.IsNaN(value) ? 0 : value);
|
||||||
|
}
|
||||||
|
|
||||||
|
[JsonPropertyName("unit")]
|
||||||
|
public ResizeUnit Unit
|
||||||
|
{
|
||||||
|
get => _unit;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (SetProperty(ref _unit, value))
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(IsHeightUsed)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets access to all properties for formatting accessibility descriptions.
|
||||||
|
/// </summary>
|
||||||
|
[JsonIgnore]
|
||||||
|
public ImageSize AccessibleTextHelper => this;
|
||||||
|
|
||||||
|
public string ToJsonString() => JsonSerializer.Serialize(this);
|
||||||
}
|
}
|
||||||
|
|
|
@ -205,7 +205,7 @@ namespace ViewModelTests
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
public void AddRowShouldAddNewImageSizeWhenSuccessful()
|
public void AddImageSizeShouldAddNewImageSizeWhenSuccessful()
|
||||||
{
|
{
|
||||||
// arrange
|
// arrange
|
||||||
var mockSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<ImageResizerSettings>();
|
var mockSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<ImageResizerSettings>();
|
||||||
|
@ -214,7 +214,7 @@ namespace ViewModelTests
|
||||||
int sizeOfOriginalArray = viewModel.Sizes.Count;
|
int sizeOfOriginalArray = viewModel.Sizes.Count;
|
||||||
|
|
||||||
// act
|
// act
|
||||||
viewModel.AddRow("New size");
|
viewModel.AddImageSize();
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.AreEqual(sizeOfOriginalArray + 1, viewModel.Sizes.Count);
|
Assert.AreEqual(sizeOfOriginalArray + 1, viewModel.Sizes.Count);
|
||||||
|
@ -229,15 +229,15 @@ namespace ViewModelTests
|
||||||
ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(_mockGeneralSettingsUtils.Object), sendMockIPCConfigMSG, (string name) => name);
|
ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(_mockGeneralSettingsUtils.Object), sendMockIPCConfigMSG, (string name) => name);
|
||||||
|
|
||||||
// act
|
// act
|
||||||
viewModel.AddRow("New size");
|
viewModel.AddImageSize("New size");
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
ImageSize newTestSize = viewModel.Sizes.First(x => x.Id == 0);
|
ImageSize newTestSize = viewModel.Sizes.First(x => x.Id == 0);
|
||||||
Assert.AreEqual(newTestSize.Name, "New size 1");
|
Assert.AreEqual("New size 1", newTestSize.Name);
|
||||||
Assert.AreEqual(newTestSize.Fit, ResizeFit.Fit);
|
Assert.AreEqual(ResizeFit.Fit, newTestSize.Fit);
|
||||||
Assert.AreEqual(newTestSize.Width, 854);
|
Assert.AreEqual(1024, newTestSize.Width);
|
||||||
Assert.AreEqual(newTestSize.Height, 480);
|
Assert.AreEqual(640, newTestSize.Height);
|
||||||
Assert.AreEqual(newTestSize.Unit, ResizeUnit.Pixel);
|
Assert.AreEqual(ResizeUnit.Pixel, newTestSize.Unit);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
@ -247,7 +247,7 @@ namespace ViewModelTests
|
||||||
var mockSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<ImageResizerSettings>();
|
var mockSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<ImageResizerSettings>();
|
||||||
Func<string, int> sendMockIPCConfigMSG = msg => { return 0; };
|
Func<string, int> sendMockIPCConfigMSG = msg => { return 0; };
|
||||||
ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(_mockGeneralSettingsUtils.Object), sendMockIPCConfigMSG, (string name) => name);
|
ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(_mockGeneralSettingsUtils.Object), sendMockIPCConfigMSG, (string name) => name);
|
||||||
viewModel.AddRow("New Size");
|
viewModel.AddImageSize("New Size");
|
||||||
int sizeOfOriginalArray = viewModel.Sizes.Count;
|
int sizeOfOriginalArray = viewModel.Sizes.Count;
|
||||||
ImageSize deleteCandidate = viewModel.Sizes.First(x => x.Id == 0);
|
ImageSize deleteCandidate = viewModel.Sizes.First(x => x.Id == 0);
|
||||||
|
|
||||||
|
@ -268,16 +268,16 @@ namespace ViewModelTests
|
||||||
ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(_mockGeneralSettingsUtils.Object), sendMockIPCConfigMSG, (string name) => name);
|
ImageResizerViewModel viewModel = new ImageResizerViewModel(mockSettingsUtils.Object, SettingsRepository<GeneralSettings>.GetInstance(_mockGeneralSettingsUtils.Object), sendMockIPCConfigMSG, (string name) => name);
|
||||||
|
|
||||||
// act
|
// act
|
||||||
viewModel.AddRow("New size"); // Add: "New size 1"
|
viewModel.AddImageSize("New size"); // Add: "New size 1"
|
||||||
viewModel.AddRow("New size"); // Add: "New size 2"
|
viewModel.AddImageSize("New size"); // Add: "New size 2"
|
||||||
viewModel.AddRow("New size"); // Add: "New size 3"
|
viewModel.AddImageSize("New size"); // Add: "New size 3"
|
||||||
viewModel.DeleteImageSize(1); // Delete: "New size 2"
|
viewModel.DeleteImageSize(1); // Delete: "New size 2"
|
||||||
viewModel.AddRow("New size"); // Add: "New Size 4"
|
viewModel.AddImageSize("New size"); // Add: "New Size 4"
|
||||||
|
|
||||||
// Assert
|
// Assert
|
||||||
Assert.AreEqual(viewModel.Sizes[0].Name, "New size 1");
|
Assert.AreEqual("New size 1", viewModel.Sizes[0].Name);
|
||||||
Assert.AreEqual(viewModel.Sizes[1].Name, "New size 3");
|
Assert.AreEqual("New size 3", viewModel.Sizes[1].Name);
|
||||||
Assert.AreEqual(viewModel.Sizes[2].Name, "New size 4");
|
Assert.AreEqual("New size 4", viewModel.Sizes[2].Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
[TestMethod]
|
[TestMethod]
|
||||||
|
|
|
@ -3,41 +3,38 @@
|
||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Windows;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
using Microsoft.UI.Xaml.Data;
|
using Microsoft.UI.Xaml.Data;
|
||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI.Converters
|
namespace Microsoft.PowerToys.Settings.UI.Converters;
|
||||||
|
|
||||||
|
public sealed partial class ImageResizerFitToStringConverter : IValueConverter
|
||||||
{
|
{
|
||||||
public sealed partial class ImageResizerFitToStringConverter : IValueConverter
|
// Maps each ResizeFit to its localized string.
|
||||||
|
private static readonly Dictionary<ResizeFit, string> FitToText = new()
|
||||||
{
|
{
|
||||||
public object Convert(object value, Type targetType, object parameter, string language)
|
{ ResizeFit.Fill, Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Fit_Fill_ThirdPersonSingular") },
|
||||||
|
{ ResizeFit.Fit, Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Fit_Fit_ThirdPersonSingular") },
|
||||||
|
{ ResizeFit.Stretch, Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Fit_Stretch_ThirdPersonSingular") },
|
||||||
|
};
|
||||||
|
|
||||||
|
public object Convert(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
if (value is ResizeFit fit && FitToText.TryGetValue(fit, out string fitText))
|
||||||
{
|
{
|
||||||
var toLower = false;
|
return parameter is string lowerParam && lowerParam == "ToLower" ?
|
||||||
if ((string)parameter == "ToLower")
|
fitText.ToLower(CultureInfo.CurrentCulture) :
|
||||||
{
|
fitText;
|
||||||
toLower = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
string targetValue = string.Empty;
|
|
||||||
switch (value)
|
|
||||||
{
|
|
||||||
case 0: targetValue = Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Fit_Fill_ThirdPersonSingular"); break;
|
|
||||||
case 1: targetValue = Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Fit_Fit_ThirdPersonSingular"); break;
|
|
||||||
case 2: targetValue = Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Fit_Stretch_ThirdPersonSingular"); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toLower)
|
|
||||||
{
|
|
||||||
targetValue = targetValue.ToLower(CultureInfo.CurrentCulture);
|
|
||||||
}
|
|
||||||
|
|
||||||
return targetValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
return DependencyProperty.UnsetValue;
|
||||||
{
|
}
|
||||||
return value;
|
|
||||||
}
|
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
// Copyright (c) Microsoft Corporation
|
||||||
|
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Globalization;
|
||||||
|
using System.Windows;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
|
using Microsoft.UI.Xaml.Data;
|
||||||
|
|
||||||
|
namespace Microsoft.PowerToys.Settings.UI.Converters;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Creates accessibility text for controls related to <see cref="ImageSize"/> properties.
|
||||||
|
/// </summary>
|
||||||
|
/// <example>(Name) "Edit the Small preset"</example>
|
||||||
|
/// <example>(FullDescription) "Large - Fits within 1920 × 1080 pixels"</example>"
|
||||||
|
public sealed partial class ImageResizerSizeToAccessibleTextConverter : IValueConverter
|
||||||
|
{
|
||||||
|
private const char TimesGlyph = '\u00D7'; // Unicode "MULTIPLICATION SIGN"
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Maps the supplied accessibility identifier to the format string of the localized accessible text.
|
||||||
|
/// </summary>
|
||||||
|
private static readonly Dictionary<string, string> AccessibilityFormats = new()
|
||||||
|
{
|
||||||
|
{ "Edit", Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_EditButton_Accessibility_Name") },
|
||||||
|
{ "Remove", Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_RemoveButton_Accessibility_Name") },
|
||||||
|
};
|
||||||
|
|
||||||
|
private readonly ImageResizerFitToStringConverter _fitConverter = new();
|
||||||
|
private readonly ImageResizerUnitToStringConverter _unitConverter = new();
|
||||||
|
|
||||||
|
public object Convert(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
return (value, parameter) switch
|
||||||
|
{
|
||||||
|
(string presetName, string nameId) => FormatNameText(presetName, nameId),
|
||||||
|
(ImageSize preset, string _) => FormatDescriptionText(preset),
|
||||||
|
_ => DependencyProperty.UnsetValue,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private object FormatNameText(string presetName, string nameId)
|
||||||
|
{
|
||||||
|
return AccessibilityFormats.TryGetValue(nameId, out string format) ?
|
||||||
|
string.Format(CultureInfo.CurrentCulture, format, presetName) :
|
||||||
|
DependencyProperty.UnsetValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
private object FormatDescriptionText(ImageSize preset)
|
||||||
|
{
|
||||||
|
if (preset == null)
|
||||||
|
{
|
||||||
|
return DependencyProperty.UnsetValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
string fitText = _fitConverter.Convert(preset.Fit, typeof(string), null, null) as string;
|
||||||
|
string unitText = _unitConverter.Convert(preset.Unit, typeof(string), null, null) as string;
|
||||||
|
|
||||||
|
return preset.IsHeightUsed ?
|
||||||
|
$"{preset.Name} - {fitText} {preset.Width} {TimesGlyph} {preset.Height} {unitText}" :
|
||||||
|
$"{preset.Name} - {fitText} {preset.Width} {unitText}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
|
@ -3,42 +3,39 @@
|
||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
|
using System.Windows;
|
||||||
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
using Microsoft.UI.Xaml.Data;
|
using Microsoft.UI.Xaml.Data;
|
||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI.Converters
|
namespace Microsoft.PowerToys.Settings.UI.Converters;
|
||||||
|
|
||||||
|
public sealed partial class ImageResizerUnitToStringConverter : IValueConverter
|
||||||
{
|
{
|
||||||
public sealed partial class ImageResizerUnitToStringConverter : IValueConverter
|
// Maps each ResizeUnit value to its localized string.
|
||||||
|
private static readonly Dictionary<ResizeUnit, string> UnitToText = new()
|
||||||
{
|
{
|
||||||
public object Convert(object value, Type targetType, object parameter, string language)
|
{ ResizeUnit.Centimeter, Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Unit_Centimeter") },
|
||||||
|
{ ResizeUnit.Inch, Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Unit_Inch") },
|
||||||
|
{ ResizeUnit.Percent, Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Unit_Percent") },
|
||||||
|
{ ResizeUnit.Pixel, Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Unit_Pixel") },
|
||||||
|
};
|
||||||
|
|
||||||
|
public object Convert(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
if (value is ResizeUnit unit && UnitToText.TryGetValue(unit, out string unitText))
|
||||||
{
|
{
|
||||||
var toLower = false;
|
return parameter is string lowerParam && lowerParam == "ToLower" ?
|
||||||
if ((string)parameter == "ToLower")
|
unitText.ToLower(CultureInfo.CurrentCulture) :
|
||||||
{
|
unitText;
|
||||||
toLower = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
string targetValue = string.Empty;
|
|
||||||
switch (value)
|
|
||||||
{
|
|
||||||
case 0: targetValue = Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Unit_Centimeter"); break;
|
|
||||||
case 1: targetValue = Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Unit_Inch"); break;
|
|
||||||
case 2: targetValue = Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Unit_Percent"); break;
|
|
||||||
case 3: targetValue = Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_Unit_Pixel"); break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (toLower)
|
|
||||||
{
|
|
||||||
targetValue = targetValue.ToLower(CultureInfo.CurrentCulture);
|
|
||||||
}
|
|
||||||
|
|
||||||
return targetValue;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
return DependencyProperty.UnsetValue;
|
||||||
{
|
}
|
||||||
return value;
|
|
||||||
}
|
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||||
|
{
|
||||||
|
return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
<converters:ImageResizerFitToIntConverter x:Key="ImageResizerFitToIntConverter" />
|
<converters:ImageResizerFitToIntConverter x:Key="ImageResizerFitToIntConverter" />
|
||||||
<converters:ImageResizerUnitToStringConverter x:Key="ImageResizerUnitToStringConverter" />
|
<converters:ImageResizerUnitToStringConverter x:Key="ImageResizerUnitToStringConverter" />
|
||||||
<converters:ImageResizerUnitToIntConverter x:Key="ImageResizerUnitToIntConverter" />
|
<converters:ImageResizerUnitToIntConverter x:Key="ImageResizerUnitToIntConverter" />
|
||||||
|
<converters:ImageResizerSizeToAccessibleTextConverter x:Key="ImageResizerSizeToAccessibleTextConverter" />
|
||||||
<toolkitconverters:BoolToObjectConverter
|
<toolkitconverters:BoolToObjectConverter
|
||||||
x:Key="BoolToComboBoxIndexConverter"
|
x:Key="BoolToComboBoxIndexConverter"
|
||||||
FalseValue="1"
|
FalseValue="1"
|
||||||
|
@ -85,13 +86,13 @@
|
||||||
FontSize="10"
|
FontSize="10"
|
||||||
Style="{ThemeResource SecondaryTextStyle}"
|
Style="{ThemeResource SecondaryTextStyle}"
|
||||||
Text=""
|
Text=""
|
||||||
Visibility="{x:Bind EnableEtraBoxes, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
|
Visibility="{x:Bind IsHeightUsed, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Margin="0,0,4,0"
|
Margin="0,0,4,0"
|
||||||
FontWeight="SemiBold"
|
FontWeight="SemiBold"
|
||||||
Style="{ThemeResource SecondaryTextStyle}"
|
Style="{ThemeResource SecondaryTextStyle}"
|
||||||
Text="{x:Bind Height, Mode=OneWay}"
|
Text="{x:Bind Height, Mode=OneWay}"
|
||||||
Visibility="{x:Bind EnableEtraBoxes, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
|
Visibility="{x:Bind IsHeightUsed, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
|
||||||
<TextBlock
|
<TextBlock
|
||||||
Margin="0,0,4,0"
|
Margin="0,0,4,0"
|
||||||
Style="{ThemeResource SecondaryTextStyle}"
|
Style="{ThemeResource SecondaryTextStyle}"
|
||||||
|
@ -104,12 +105,20 @@
|
||||||
Orientation="Horizontal"
|
Orientation="Horizontal"
|
||||||
Spacing="8">
|
Spacing="8">
|
||||||
<Button
|
<Button
|
||||||
x:Uid="EditButton"
|
x:Uid="ImageResizer_EditButton"
|
||||||
Width="40"
|
Width="40"
|
||||||
Height="36"
|
Height="36"
|
||||||
Content=""
|
Content=""
|
||||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||||
Style="{StaticResource SubtleButtonStyle}">
|
Style="{StaticResource SubtleButtonStyle}"
|
||||||
|
AutomationProperties.Name="{x:Bind Name,
|
||||||
|
Mode=OneWay,
|
||||||
|
Converter={StaticResource ImageResizerSizeToAccessibleTextConverter},
|
||||||
|
ConverterParameter='Edit'}"
|
||||||
|
AutomationProperties.FullDescription="{x:Bind AccessibleTextHelper,
|
||||||
|
Mode=OneWay,
|
||||||
|
Converter={StaticResource ImageResizerSizeToAccessibleTextConverter},
|
||||||
|
ConverterParameter='Edit'}">
|
||||||
<ToolTipService.ToolTip>
|
<ToolTipService.ToolTip>
|
||||||
<TextBlock x:Uid="EditTooltip" />
|
<TextBlock x:Uid="EditTooltip" />
|
||||||
</ToolTipService.ToolTip>
|
</ToolTipService.ToolTip>
|
||||||
|
@ -145,10 +154,10 @@
|
||||||
Width="116"
|
Width="116"
|
||||||
Minimum="0"
|
Minimum="0"
|
||||||
SpinButtonPlacementMode="Compact"
|
SpinButtonPlacementMode="Compact"
|
||||||
Visibility="{x:Bind EnableEtraBoxes, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}"
|
Visibility="{x:Bind IsHeightUsed, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}"
|
||||||
Value="{x:Bind Height, Mode=TwoWay}" />
|
Value="{x:Bind Height, Mode=TwoWay}" />
|
||||||
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
<ComboBox
|
<ComboBox
|
||||||
x:Uid="ImageResizer_Size"
|
x:Uid="ImageResizer_Size"
|
||||||
Width="240"
|
Width="240"
|
||||||
|
@ -164,15 +173,22 @@
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<Button
|
<Button
|
||||||
x:Name="RemoveButton"
|
x:Uid="ImageResizer_RemoveButton"
|
||||||
x:Uid="RemoveButton"
|
|
||||||
Width="40"
|
Width="40"
|
||||||
Height="36"
|
Height="36"
|
||||||
Click="DeleteCustomSize"
|
Click="DeleteCustomSize"
|
||||||
CommandParameter="{Binding Id}"
|
CommandParameter="{Binding Id}"
|
||||||
Content=""
|
Content=""
|
||||||
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
FontFamily="{ThemeResource SymbolThemeFontFamily}"
|
||||||
Style="{StaticResource SubtleButtonStyle}">
|
Style="{StaticResource SubtleButtonStyle}"
|
||||||
|
AutomationProperties.Name="{x:Bind Name,
|
||||||
|
Mode=OneWay,
|
||||||
|
Converter={StaticResource ImageResizerSizeToAccessibleTextConverter},
|
||||||
|
ConverterParameter='Remove'}"
|
||||||
|
AutomationProperties.FullDescription="{x:Bind AccessibleTextHelper,
|
||||||
|
Mode=OneWay,
|
||||||
|
Converter={StaticResource ImageResizerSizeToAccessibleTextConverter},
|
||||||
|
ConverterParameter='Remove'}">
|
||||||
<ToolTipService.ToolTip>
|
<ToolTipService.ToolTip>
|
||||||
<TextBlock x:Uid="RemoveTooltip" />
|
<TextBlock x:Uid="RemoveTooltip" />
|
||||||
</ToolTipService.ToolTip>
|
</ToolTipService.ToolTip>
|
||||||
|
|
|
@ -22,11 +22,8 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
var settingsUtils = new SettingsUtils();
|
var settingsUtils = new SettingsUtils();
|
||||||
var resourceLoader = Helpers.ResourceLoaderInstance.ResourceLoader;
|
var resourceLoader = ResourceLoaderInstance.ResourceLoader;
|
||||||
Func<string, string> loader = (string name) =>
|
Func<string, string> loader = resourceLoader.GetString;
|
||||||
{
|
|
||||||
return resourceLoader.GetString(name);
|
|
||||||
};
|
|
||||||
|
|
||||||
ViewModel = new ImageResizerViewModel(settingsUtils, SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage, loader);
|
ViewModel = new ImageResizerViewModel(settingsUtils, SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage, loader);
|
||||||
DataContext = ViewModel;
|
DataContext = ViewModel;
|
||||||
|
@ -69,7 +66,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
ViewModel.AddRow(Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_DefaultSize_NewSizePrefix"));
|
ViewModel.AddImageSize();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
|
@ -1169,10 +1169,6 @@
|
||||||
<data name="ImageResizer_Size.Header" xml:space="preserve">
|
<data name="ImageResizer_Size.Header" xml:space="preserve">
|
||||||
<value>Unit</value>
|
<value>Unit</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="RemoveButton.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
|
||||||
<value>Remove</value>
|
|
||||||
<comment>Removes a user defined setting group for Image Resizer</comment>
|
|
||||||
</data>
|
|
||||||
<data name="RemoveItem.Text" xml:space="preserve">
|
<data name="RemoveItem.Text" xml:space="preserve">
|
||||||
<value>Delete</value>
|
<value>Delete</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -2352,12 +2348,29 @@ From there, simply click on one of the supported files in the File Explorer and
|
||||||
<data name="ImageResizer_Unit_Pixel" xml:space="preserve">
|
<data name="ImageResizer_Unit_Pixel" xml:space="preserve">
|
||||||
<value>Pixels</value>
|
<value>Pixels</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="EditButton.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
<data name="ImageResizer_EditButton.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||||
<value>Edit</value>
|
<value>Edit</value>
|
||||||
</data>
|
</data>
|
||||||
<data name="ImageResizer_EditSize.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
<data name="ImageResizer_EditSize.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||||
<value>Edit size</value>
|
<value>Edit size</value>
|
||||||
</data>
|
</data>
|
||||||
|
<data name="ImageResizer_Presets.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||||
|
<value>ImageResizer presets</value>
|
||||||
|
</data>
|
||||||
|
<data name="ImageResizer_AddSizeButton.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||||
|
<value>Add a new preset</value>
|
||||||
|
</data>
|
||||||
|
<data name="ImageResizer_RemoveButton.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
|
||||||
|
<value>Remove</value>
|
||||||
|
</data>
|
||||||
|
<data name="ImageResizer_EditButton_Accessibility_Name" xml:space="preserve">
|
||||||
|
<value>Edit the {0} preset</value>
|
||||||
|
<comment>Expands to the AutomationProperties.Name value for the Edit button. Example: "Edit the Small preset".</comment>
|
||||||
|
</data>
|
||||||
|
<data name="ImageResizer_RemoveButton_Accessibility_Name" xml:space="preserve">
|
||||||
|
<value>Remove the {0} preset</value>
|
||||||
|
<comment>Expands to the AutomationProperties.Name value for the Remove button. Example: "Remove the Large preset".</comment>
|
||||||
|
</data>
|
||||||
<data name="No" xml:space="preserve">
|
<data name="No" xml:space="preserve">
|
||||||
<value>No</value>
|
<value>No</value>
|
||||||
<comment>Label of a cancel button</comment>
|
<comment>Label of a cancel button</comment>
|
||||||
|
|
|
@ -3,431 +3,362 @@
|
||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Collections.Specialized;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
using global::PowerToys.GPOWrapper;
|
using global::PowerToys.GPOWrapper;
|
||||||
using ManagedCommon;
|
using ManagedCommon;
|
||||||
using Microsoft.PowerToys.Settings.UI.Library;
|
using Microsoft.PowerToys.Settings.UI.Library;
|
||||||
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
|
||||||
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
using Microsoft.PowerToys.Settings.UI.Library.Interfaces;
|
||||||
|
|
||||||
namespace Microsoft.PowerToys.Settings.UI.ViewModels
|
namespace Microsoft.PowerToys.Settings.UI.ViewModels;
|
||||||
|
|
||||||
|
public partial class ImageResizerViewModel : Observable
|
||||||
{
|
{
|
||||||
public class ImageResizerViewModel : Observable
|
private static readonly string DefaultPresetNamePrefix =
|
||||||
|
Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_DefaultSize_NewSizePrefix");
|
||||||
|
|
||||||
|
private static readonly List<string> EncoderGuids =
|
||||||
|
[
|
||||||
|
"1b7cfaf4-713f-473c-bbcd-6137425faeaf", // PNG Encoder
|
||||||
|
"0af1d87e-fcfe-4188-bdeb-a7906471cbe3", // Bitmap Encoder
|
||||||
|
"19e4a5aa-5662-4fc5-a0c0-1758028e1057", // JPEG Encoder
|
||||||
|
"163bcc30-e2e9-4f0b-961d-a3e9fdb788a3", // TIFF Encoder
|
||||||
|
"57a37caa-367a-4540-916b-f183c5093a4b", // TIFF Encoder
|
||||||
|
"1f8a5601-7d4d-4cbd-9c82-1bc8d4eeb9a5", // GIF Encoder
|
||||||
|
];
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Used to skip saving settings to file during initialization.
|
||||||
|
/// </summary>
|
||||||
|
private readonly bool _isInitializing;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Holds defaults for new presets.
|
||||||
|
/// </summary>
|
||||||
|
private readonly ImageSize _customSize;
|
||||||
|
|
||||||
|
private GeneralSettings GeneralSettingsConfig { get; set; }
|
||||||
|
|
||||||
|
private readonly ISettingsUtils _settingsUtils;
|
||||||
|
|
||||||
|
private ImageResizerSettings Settings { get; set; }
|
||||||
|
|
||||||
|
private const string ModuleName = ImageResizerSettings.ModuleName;
|
||||||
|
|
||||||
|
private Func<string, int> SendConfigMSG { get; }
|
||||||
|
|
||||||
|
public ImageResizerViewModel(ISettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc, Func<string, string> resourceLoader)
|
||||||
{
|
{
|
||||||
private GeneralSettings GeneralSettingsConfig { get; set; }
|
_isInitializing = true;
|
||||||
|
|
||||||
private readonly ISettingsUtils _settingsUtils;
|
_settingsUtils = settingsUtils ?? throw new ArgumentNullException(nameof(settingsUtils));
|
||||||
|
|
||||||
private ImageResizerSettings Settings { get; set; }
|
// To obtain the general settings configurations of PowerToys.
|
||||||
|
ArgumentNullException.ThrowIfNull(settingsRepository);
|
||||||
|
|
||||||
private const string ModuleName = ImageResizerSettings.ModuleName;
|
GeneralSettingsConfig = settingsRepository.SettingsConfig;
|
||||||
|
|
||||||
private Func<string, int> SendConfigMSG { get; }
|
try
|
||||||
|
|
||||||
public ImageResizerViewModel(ISettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc, Func<string, string> resourceLoader)
|
|
||||||
{
|
{
|
||||||
_settingsUtils = settingsUtils ?? throw new ArgumentNullException(nameof(settingsUtils));
|
Settings = _settingsUtils.GetSettings<ImageResizerSettings>(ModuleName);
|
||||||
|
}
|
||||||
// To obtain the general settings configurations of PowerToys.
|
catch (Exception e)
|
||||||
ArgumentNullException.ThrowIfNull(settingsRepository);
|
{
|
||||||
|
Logger.LogError($"Exception encountered while reading {ModuleName} settings.", e);
|
||||||
GeneralSettingsConfig = settingsRepository.SettingsConfig;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Settings = _settingsUtils.GetSettings<ImageResizerSettings>(ModuleName);
|
|
||||||
}
|
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
Logger.LogError($"Exception encountered while reading {ModuleName} settings.", e);
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
if (e is ArgumentException || e is ArgumentNullException || e is PathTooLongException)
|
if (e is ArgumentException || e is ArgumentNullException || e is PathTooLongException)
|
||||||
{
|
{
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
Settings = new ImageResizerSettings(resourceLoader);
|
Settings = new ImageResizerSettings(resourceLoader);
|
||||||
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// set the callback functions value to handle outgoing IPC message.
|
|
||||||
SendConfigMSG = ipcMSGCallBackFunc;
|
|
||||||
|
|
||||||
InitializeEnabledValue();
|
|
||||||
|
|
||||||
_advancedSizes = Settings.Properties.ImageresizerSizes.Value;
|
|
||||||
_jpegQualityLevel = Settings.Properties.ImageresizerJpegQualityLevel.Value;
|
|
||||||
_pngInterlaceOption = Settings.Properties.ImageresizerPngInterlaceOption.Value;
|
|
||||||
_tiffCompressOption = Settings.Properties.ImageresizerTiffCompressOption.Value;
|
|
||||||
_fileName = Settings.Properties.ImageresizerFileName.Value;
|
|
||||||
_keepDateModified = Settings.Properties.ImageresizerKeepDateModified.Value;
|
|
||||||
_encoderGuidId = GetEncoderIndex(Settings.Properties.ImageresizerFallbackEncoder.Value);
|
|
||||||
|
|
||||||
int i = 0;
|
|
||||||
foreach (ImageSize size in _advancedSizes)
|
|
||||||
{
|
|
||||||
size.Id = i;
|
|
||||||
i++;
|
|
||||||
size.PropertyChanged += SizePropertyChanged;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeEnabledValue()
|
|
||||||
{
|
|
||||||
_enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredImageResizerEnabledValue();
|
|
||||||
if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
|
|
||||||
{
|
|
||||||
// Get the enabled state from GPO.
|
|
||||||
_enabledStateIsGPOConfigured = true;
|
|
||||||
_isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_isEnabled = GeneralSettingsConfig.Enabled.ImageResizer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private GpoRuleConfigured _enabledGpoRuleConfiguration;
|
|
||||||
private bool _enabledStateIsGPOConfigured;
|
|
||||||
private bool _isEnabled;
|
|
||||||
private ObservableCollection<ImageSize> _advancedSizes = new ObservableCollection<ImageSize>();
|
|
||||||
private int _jpegQualityLevel;
|
|
||||||
private int _pngInterlaceOption;
|
|
||||||
private int _tiffCompressOption;
|
|
||||||
private string _fileName;
|
|
||||||
private bool _keepDateModified;
|
|
||||||
private int _encoderGuidId;
|
|
||||||
|
|
||||||
public bool IsListViewFocusRequested { get; set; }
|
|
||||||
|
|
||||||
public bool IsEnabled
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _isEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_enabledStateIsGPOConfigured)
|
|
||||||
{
|
|
||||||
// If it's GPO configured, shouldn't be able to change this state.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (value != _isEnabled)
|
|
||||||
{
|
|
||||||
// To set the status of ImageResizer in the General PowerToys settings.
|
|
||||||
_isEnabled = value;
|
|
||||||
GeneralSettingsConfig.Enabled.ImageResizer = value;
|
|
||||||
OutGoingGeneralSettings snd = new OutGoingGeneralSettings(GeneralSettingsConfig);
|
|
||||||
|
|
||||||
SendConfigMSG(snd.ToString());
|
|
||||||
OnPropertyChanged(nameof(IsEnabled));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsEnabledGpoConfigured
|
|
||||||
{
|
|
||||||
get => _enabledStateIsGPOConfigured;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableCollection<ImageSize> Sizes
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _advancedSizes;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
SavesImageSizes(value);
|
|
||||||
_advancedSizes = value;
|
|
||||||
OnPropertyChanged(nameof(Sizes));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int JPEGQualityLevel
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _jpegQualityLevel;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_jpegQualityLevel != value)
|
|
||||||
{
|
|
||||||
_jpegQualityLevel = value;
|
|
||||||
Settings.Properties.ImageresizerJpegQualityLevel.Value = value;
|
|
||||||
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
|
|
||||||
OnPropertyChanged(nameof(JPEGQualityLevel));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int PngInterlaceOption
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _pngInterlaceOption;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_pngInterlaceOption != value)
|
|
||||||
{
|
|
||||||
_pngInterlaceOption = value;
|
|
||||||
Settings.Properties.ImageresizerPngInterlaceOption.Value = value;
|
|
||||||
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
|
|
||||||
OnPropertyChanged(nameof(PngInterlaceOption));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int TiffCompressOption
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _tiffCompressOption;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_tiffCompressOption != value)
|
|
||||||
{
|
|
||||||
_tiffCompressOption = value;
|
|
||||||
Settings.Properties.ImageresizerTiffCompressOption.Value = value;
|
|
||||||
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
|
|
||||||
OnPropertyChanged(nameof(TiffCompressOption));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string FileName
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _fileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (!string.IsNullOrWhiteSpace(value))
|
|
||||||
{
|
|
||||||
_fileName = value;
|
|
||||||
Settings.Properties.ImageresizerFileName.Value = value;
|
|
||||||
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
|
|
||||||
OnPropertyChanged(nameof(FileName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool KeepDateModified
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _keepDateModified;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
_keepDateModified = value;
|
|
||||||
Settings.Properties.ImageresizerKeepDateModified.Value = value;
|
|
||||||
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
|
|
||||||
OnPropertyChanged(nameof(KeepDateModified));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Encoder
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return _encoderGuidId;
|
|
||||||
}
|
|
||||||
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_encoderGuidId != value)
|
|
||||||
{
|
|
||||||
_encoderGuidId = value;
|
|
||||||
_settingsUtils.SaveSettings(Settings.Properties.ImageresizerSizes.ToJsonString(), ModuleName, "sizes.json");
|
|
||||||
Settings.Properties.ImageresizerFallbackEncoder.Value = GetEncoderGuid(value);
|
|
||||||
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
|
|
||||||
OnPropertyChanged(nameof(Encoder));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public string EncoderGuid
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
return ImageResizerViewModel.GetEncoderGuid(_encoderGuidId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddRow(string sizeNamePrefix)
|
|
||||||
{
|
|
||||||
/// This is a fallback validation to eliminate the warning "CA1062:Validate arguments of public methods" when using the parameter (variable) "sizeNamePrefix" in the code.
|
|
||||||
/// If the parameter is unexpectedly empty or null, we fill the parameter with a non-localized string.
|
|
||||||
/// Normally the parameter "sizeNamePrefix" can't be null or empty because it is filled with a localized string when we call this method from <see cref="UI.Views.ImageResizerPage.AddSizeButton_Click"/>.
|
|
||||||
sizeNamePrefix = string.IsNullOrEmpty(sizeNamePrefix) ? "New Size" : sizeNamePrefix;
|
|
||||||
|
|
||||||
ObservableCollection<ImageSize> imageSizes = Sizes;
|
|
||||||
int maxId = imageSizes.Count > 0 ? imageSizes.OrderBy(x => x.Id).Last().Id : -1;
|
|
||||||
string sizeName = GenerateNameForNewSize(imageSizes, sizeNamePrefix);
|
|
||||||
|
|
||||||
ImageSize newSize = new ImageSize(maxId + 1, sizeName, ResizeFit.Fit, 854, 480, ResizeUnit.Pixel);
|
|
||||||
newSize.PropertyChanged += SizePropertyChanged;
|
|
||||||
imageSizes.Add(newSize);
|
|
||||||
_advancedSizes = imageSizes;
|
|
||||||
SavesImageSizes(imageSizes);
|
|
||||||
|
|
||||||
// Set the focus requested flag to indicate that an add operation has occurred during the ContainerContentChanging event
|
|
||||||
IsListViewFocusRequested = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void DeleteImageSize(int id)
|
|
||||||
{
|
|
||||||
ImageSize size = _advancedSizes.First(x => x.Id == id);
|
|
||||||
ObservableCollection<ImageSize> imageSizes = Sizes;
|
|
||||||
imageSizes.Remove(size);
|
|
||||||
|
|
||||||
_advancedSizes = imageSizes;
|
|
||||||
SavesImageSizes(imageSizes);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SavesImageSizes(ObservableCollection<ImageSize> imageSizes)
|
|
||||||
{
|
|
||||||
_settingsUtils.SaveSettings(Settings.Properties.ImageresizerSizes.ToJsonString(), ModuleName, "sizes.json");
|
|
||||||
Settings.Properties.ImageresizerSizes = new ImageResizerSizes(imageSizes);
|
|
||||||
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
|
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string GetEncoderGuid(int value)
|
// set the callback functions value to handle outgoing IPC message.
|
||||||
|
SendConfigMSG = ipcMSGCallBackFunc;
|
||||||
|
|
||||||
|
InitializeEnabledValue();
|
||||||
|
|
||||||
|
Sizes = new ObservableCollection<ImageSize>(Settings.Properties.ImageresizerSizes.Value);
|
||||||
|
JPEGQualityLevel = Settings.Properties.ImageresizerJpegQualityLevel.Value;
|
||||||
|
PngInterlaceOption = Settings.Properties.ImageresizerPngInterlaceOption.Value;
|
||||||
|
TiffCompressOption = Settings.Properties.ImageresizerTiffCompressOption.Value;
|
||||||
|
FileName = Settings.Properties.ImageresizerFileName.Value;
|
||||||
|
KeepDateModified = Settings.Properties.ImageresizerKeepDateModified.Value;
|
||||||
|
Encoder = GetEncoderIndex(Settings.Properties.ImageresizerFallbackEncoder.Value);
|
||||||
|
|
||||||
|
_customSize = Settings.Properties.ImageresizerCustomSize.Value;
|
||||||
|
|
||||||
|
_isInitializing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializeEnabledValue()
|
||||||
|
{
|
||||||
|
_enabledGpoRuleConfiguration = GPOWrapper.GetConfiguredImageResizerEnabledValue();
|
||||||
|
if (_enabledGpoRuleConfiguration == GpoRuleConfigured.Disabled || _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled)
|
||||||
{
|
{
|
||||||
// PNG Encoder guid
|
// Get the enabled state from GPO.
|
||||||
if (value == 0)
|
_enabledStateIsGPOConfigured = true;
|
||||||
{
|
_isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
|
||||||
return "1b7cfaf4-713f-473c-bbcd-6137425faeaf";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bitmap Encoder guid
|
|
||||||
else if (value == 1)
|
|
||||||
{
|
|
||||||
return "0af1d87e-fcfe-4188-bdeb-a7906471cbe3";
|
|
||||||
}
|
|
||||||
|
|
||||||
// JPEG Encoder guid
|
|
||||||
else if (value == 2)
|
|
||||||
{
|
|
||||||
return "19e4a5aa-5662-4fc5-a0c0-1758028e1057";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tiff encoder guid.
|
|
||||||
else if (value == 3)
|
|
||||||
{
|
|
||||||
return "163bcc30-e2e9-4f0b-961d-a3e9fdb788a3";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tiff encoder guid.
|
|
||||||
else if (value == 4)
|
|
||||||
{
|
|
||||||
return "57a37caa-367a-4540-916b-f183c5093a4b";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gif encoder guid.
|
|
||||||
else if (value == 5)
|
|
||||||
{
|
|
||||||
return "1f8a5601-7d4d-4cbd-9c82-1bc8d4eeb9a5";
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
else
|
||||||
public static int GetEncoderIndex(string value)
|
|
||||||
{
|
{
|
||||||
// PNG Encoder guid
|
_isEnabled = GeneralSettingsConfig.Enabled.ImageResizer;
|
||||||
if (value == "1b7cfaf4-713f-473c-bbcd-6137425faeaf")
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bitmap Encoder guid
|
|
||||||
else if (value == "0af1d87e-fcfe-4188-bdeb-a7906471cbe3")
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// JPEG Encoder guid
|
|
||||||
else if (value == "19e4a5aa-5662-4fc5-a0c0-1758028e1057")
|
|
||||||
{
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tiff encoder guid.
|
|
||||||
else if (value == "163bcc30-e2e9-4f0b-961d-a3e9fdb788a3")
|
|
||||||
{
|
|
||||||
return 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Tiff encoder guid.
|
|
||||||
else if (value == "57a37caa-367a-4540-916b-f183c5093a4b")
|
|
||||||
{
|
|
||||||
return 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Gif encoder guid.
|
|
||||||
else if (value == "1f8a5601-7d4d-4cbd-9c82-1bc8d4eeb9a5")
|
|
||||||
{
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void SizePropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
ImageSize modifiedSize = (ImageSize)sender;
|
|
||||||
ObservableCollection<ImageSize> imageSizes = Sizes;
|
|
||||||
imageSizes.First(x => x.Id == modifiedSize.Id).Update(modifiedSize);
|
|
||||||
_advancedSizes = imageSizes;
|
|
||||||
SavesImageSizes(imageSizes);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static string GenerateNameForNewSize(in ObservableCollection<ImageSize> sizesList, in string namePrefix)
|
|
||||||
{
|
|
||||||
int newSizeCounter = 0;
|
|
||||||
|
|
||||||
foreach (ImageSize imgSize in sizesList)
|
|
||||||
{
|
|
||||||
string name = imgSize.Name;
|
|
||||||
|
|
||||||
if (name.StartsWith(namePrefix, StringComparison.InvariantCulture))
|
|
||||||
{
|
|
||||||
if (int.TryParse(name.AsSpan(namePrefix.Length), out int number))
|
|
||||||
{
|
|
||||||
if (newSizeCounter < number)
|
|
||||||
{
|
|
||||||
newSizeCounter = number;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return $"{namePrefix} {++newSizeCounter}";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RefreshEnabledState()
|
|
||||||
{
|
|
||||||
InitializeEnabledValue();
|
|
||||||
OnPropertyChanged(nameof(IsEnabled));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private GpoRuleConfigured _enabledGpoRuleConfiguration;
|
||||||
|
private bool _enabledStateIsGPOConfigured;
|
||||||
|
private bool _isEnabled;
|
||||||
|
private ObservableCollection<ImageSize> _sizes = [];
|
||||||
|
private int _jpegQualityLevel;
|
||||||
|
private int _pngInterlaceOption;
|
||||||
|
private int _tiffCompressOption;
|
||||||
|
private string _fileName;
|
||||||
|
private bool _keepDateModified;
|
||||||
|
private int _encoderGuidId;
|
||||||
|
|
||||||
|
public bool IsListViewFocusRequested { get; set; }
|
||||||
|
|
||||||
|
public bool IsEnabled
|
||||||
|
{
|
||||||
|
get => _isEnabled;
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_enabledStateIsGPOConfigured)
|
||||||
|
{
|
||||||
|
// If it's GPO configured, shouldn't be able to change this state.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value != _isEnabled)
|
||||||
|
{
|
||||||
|
// To set the status of ImageResizer in the General PowerToys settings.
|
||||||
|
_isEnabled = value;
|
||||||
|
GeneralSettingsConfig.Enabled.ImageResizer = value;
|
||||||
|
OutGoingGeneralSettings snd = new OutGoingGeneralSettings(GeneralSettingsConfig);
|
||||||
|
|
||||||
|
SendConfigMSG(snd.ToString());
|
||||||
|
OnPropertyChanged(nameof(IsEnabled));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsEnabledGpoConfigured
|
||||||
|
{
|
||||||
|
get => _enabledStateIsGPOConfigured;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ObservableCollection<ImageSize> Sizes
|
||||||
|
{
|
||||||
|
get => _sizes;
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (_sizes != null)
|
||||||
|
{
|
||||||
|
_sizes.CollectionChanged -= Sizes_CollectionChanged;
|
||||||
|
UnsubscribeFromItemPropertyChanged(_sizes);
|
||||||
|
}
|
||||||
|
|
||||||
|
_sizes = value;
|
||||||
|
|
||||||
|
if (_sizes != null)
|
||||||
|
{
|
||||||
|
_sizes.CollectionChanged += Sizes_CollectionChanged;
|
||||||
|
SubscribeToItemPropertyChanged(_sizes);
|
||||||
|
}
|
||||||
|
|
||||||
|
OnPropertyChanged(nameof(Sizes));
|
||||||
|
|
||||||
|
if (!_isInitializing)
|
||||||
|
{
|
||||||
|
SaveImageSizes();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Sizes_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||||
|
{
|
||||||
|
SubscribeToItemPropertyChanged(e.NewItems?.Cast<ImageSize>());
|
||||||
|
UnsubscribeFromItemPropertyChanged(e.OldItems?.Cast<ImageSize>());
|
||||||
|
SaveImageSizes();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SubscribeToItemPropertyChanged(IEnumerable<ImageSize> items)
|
||||||
|
{
|
||||||
|
if (items != null)
|
||||||
|
{
|
||||||
|
foreach (var item in items)
|
||||||
|
{
|
||||||
|
item.PropertyChanged += SizePropertyChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UnsubscribeFromItemPropertyChanged(IEnumerable<ImageSize> items)
|
||||||
|
{
|
||||||
|
if (items != null)
|
||||||
|
{
|
||||||
|
foreach (var item in items)
|
||||||
|
{
|
||||||
|
item.PropertyChanged -= SizePropertyChanged;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetProperty<T>(ref T backingField, T value, Action<T> updateSettingsAction, [CallerMemberName] string propertyName = null)
|
||||||
|
{
|
||||||
|
if (!EqualityComparer<T>.Default.Equals(backingField, value))
|
||||||
|
{
|
||||||
|
backingField = value;
|
||||||
|
|
||||||
|
if (!_isInitializing)
|
||||||
|
{
|
||||||
|
updateSettingsAction(value);
|
||||||
|
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
OnPropertyChanged(propertyName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int JPEGQualityLevel
|
||||||
|
{
|
||||||
|
get => _jpegQualityLevel;
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetProperty(ref _jpegQualityLevel, value, v => Settings.Properties.ImageresizerJpegQualityLevel.Value = v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int PngInterlaceOption
|
||||||
|
{
|
||||||
|
get => _pngInterlaceOption;
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetProperty(ref _pngInterlaceOption, value, v => Settings.Properties.ImageresizerPngInterlaceOption.Value = v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int TiffCompressOption
|
||||||
|
{
|
||||||
|
get => _tiffCompressOption;
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetProperty(ref _tiffCompressOption, value, v => Settings.Properties.ImageresizerTiffCompressOption.Value = v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string FileName
|
||||||
|
{
|
||||||
|
get => _fileName;
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!string.IsNullOrWhiteSpace(value))
|
||||||
|
{
|
||||||
|
SetProperty(ref _fileName, value, v => Settings.Properties.ImageresizerFileName.Value = v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool KeepDateModified
|
||||||
|
{
|
||||||
|
get => _keepDateModified;
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetProperty(ref _keepDateModified, value, v => Settings.Properties.ImageresizerKeepDateModified.Value = v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public int Encoder
|
||||||
|
{
|
||||||
|
get => _encoderGuidId;
|
||||||
|
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SetProperty(ref _encoderGuidId, value, v => Settings.Properties.ImageresizerFallbackEncoder.Value = GetEncoderGuid(v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public string EncoderGuid => GetEncoderGuid(_encoderGuidId);
|
||||||
|
|
||||||
|
public static string GetEncoderGuid(int index) =>
|
||||||
|
index < 0 || index >= EncoderGuids.Count ? throw new ArgumentOutOfRangeException(nameof(index)) : EncoderGuids[index];
|
||||||
|
|
||||||
|
public static int GetEncoderIndex(string encoderGuid)
|
||||||
|
{
|
||||||
|
int index = EncoderGuids.IndexOf(encoderGuid);
|
||||||
|
return index == -1 ? throw new ArgumentException("Encoder GUID not found.", nameof(encoderGuid)) : index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddImageSize(string namePrefix = "")
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(namePrefix))
|
||||||
|
{
|
||||||
|
namePrefix = DefaultPresetNamePrefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
int maxId = Sizes.Count > 0 ? Sizes.Max(x => x.Id) : -1;
|
||||||
|
string sizeName = GenerateNameForNewSize(namePrefix);
|
||||||
|
|
||||||
|
Sizes.Add(new ImageSize(maxId + 1, GenerateNameForNewSize(namePrefix), _customSize.Fit, _customSize.Width, _customSize.Height, _customSize.Unit));
|
||||||
|
|
||||||
|
// Set the focus requested flag to indicate that an add operation has occurred during the ContainerContentChanging event
|
||||||
|
IsListViewFocusRequested = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void DeleteImageSize(int id)
|
||||||
|
{
|
||||||
|
ImageSize size = _sizes.First(x => x.Id == id);
|
||||||
|
Sizes.Remove(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveImageSizes()
|
||||||
|
{
|
||||||
|
Settings.Properties.ImageresizerSizes = new ImageResizerSizes(Sizes);
|
||||||
|
_settingsUtils.SaveSettings(Settings.Properties.ImageresizerSizes.ToJsonString(), ModuleName, "sizes.json");
|
||||||
|
_settingsUtils.SaveSettings(Settings.ToJsonString(), ModuleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SizePropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
|
{
|
||||||
|
SaveImageSizes();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string GenerateNameForNewSize(string namePrefix)
|
||||||
|
{
|
||||||
|
int newSizeCounter = 0;
|
||||||
|
|
||||||
|
foreach (var name in Sizes.Select(x => x.Name))
|
||||||
|
{
|
||||||
|
if (name.StartsWith(namePrefix, StringComparison.InvariantCulture) &&
|
||||||
|
int.TryParse(name.AsSpan(namePrefix.Length), out int number) &&
|
||||||
|
newSizeCounter < number)
|
||||||
|
{
|
||||||
|
newSizeCounter = number;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $"{namePrefix} {++newSizeCounter}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RefreshEnabledState()
|
||||||
|
{
|
||||||
|
InitializeEnabledValue();
|
||||||
|
OnPropertyChanged(nameof(IsEnabled));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче