Merge remote-tracking branch 'origin/main' into Workspaces_LaunchNoMonitor

This commit is contained in:
donlaci 2025-01-22 13:37:44 +01:00
Родитель 5259f4d202 ab8df1a906
Коммит 087789e3d5
11 изменённых файлов: 630 добавлений и 724 удалений

Просмотреть файл

@ -343,6 +343,21 @@ namespace newplus::utilities
}
}
inline void update_last_write_time(const std::filesystem::path path)
{
const std::filesystem::file_time_type now = std::filesystem::file_time_type::clock::now();
std::filesystem::last_write_time(path, now);
if (std::filesystem::is_directory(path))
{
for (const auto& entry : std::filesystem::recursive_directory_iterator(path))
{
std::filesystem::last_write_time(entry.path(), now);
}
}
}
inline HRESULT copy_template(const template_item* template_entry, const ComPtr<IUnknown> site_of_folder)
{
HRESULT hr = S_OK;
@ -376,6 +391,9 @@ namespace newplus::utilities
// Copy file and determine final filename
std::filesystem::path target_final_fullpath = template_entry->copy_object_to(GetActiveWindow(), target_fullpath);
// Touch all files and set last modified to "now"
update_last_write_time(target_final_fullpath);
// Consider copy completed. If we do tracing after enter_rename_mode, then rename mode won't consistently work
trace.UpdateState(true);
Trace::EventCopyTemplate(target_final_fullpath.extension().c_str());

Просмотреть файл

@ -7416,6 +7416,12 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
if( !ShowEula( APPNAME, NULL, NULL )) return 1;
#ifdef __ZOOMIT_POWERTOYS__
if (powertoys_gpo::getConfiguredZoomItEnabledValue() == powertoys_gpo::gpo_rule_configured_disabled)
{
Logger::warn(L"Tried to start with a GPO policy setting the utility to always be disabled. Please contact your systems administrator.");
return 1;
}
Shared::Trace::ETWTrace* trace = nullptr;
std::wstring pid = std::wstring(lpCmdLine); // The PowerToys pid is the argument to the process.
auto mainThreadId = GetCurrentThreadId();
@ -7423,12 +7429,6 @@ int APIENTRY wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
{
g_StartedByPowerToys = TRUE;
if (powertoys_gpo::getConfiguredZoomItEnabledValue() == powertoys_gpo::gpo_rule_configured_disabled)
{
Logger::warn(L"Tried to start with a GPO policy setting the utility to always be disabled. Please contact your systems administrator.");
return 1;
}
trace = new Shared::Trace::ETWTrace();
Trace::RegisterProvider();
trace->UpdateState(true);

Просмотреть файл

@ -3,241 +3,119 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Text.Json;
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;
Name = string.Empty;
Fit = ResizeFit.Fit;
Width = 0;
Height = 0;
Unit = ResizeUnit.Pixel;
field = value;
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(AccessibleTextHelper)));
}
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;
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
if (SetProperty(ref _fit, value))
{
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]
public void AddRowShouldAddNewImageSizeWhenSuccessful()
public void AddImageSizeShouldAddNewImageSizeWhenSuccessful()
{
// arrange
var mockSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<ImageResizerSettings>();
@ -214,7 +214,7 @@ namespace ViewModelTests
int sizeOfOriginalArray = viewModel.Sizes.Count;
// act
viewModel.AddRow("New size");
viewModel.AddImageSize();
// Assert
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);
// act
viewModel.AddRow("New size");
viewModel.AddImageSize("New size");
// Assert
ImageSize newTestSize = viewModel.Sizes.First(x => x.Id == 0);
Assert.AreEqual(newTestSize.Name, "New size 1");
Assert.AreEqual(newTestSize.Fit, ResizeFit.Fit);
Assert.AreEqual(newTestSize.Width, 854);
Assert.AreEqual(newTestSize.Height, 480);
Assert.AreEqual(newTestSize.Unit, ResizeUnit.Pixel);
Assert.AreEqual("New size 1", newTestSize.Name);
Assert.AreEqual(ResizeFit.Fit, newTestSize.Fit);
Assert.AreEqual(1024, newTestSize.Width);
Assert.AreEqual(640, newTestSize.Height);
Assert.AreEqual(ResizeUnit.Pixel, newTestSize.Unit);
}
[TestMethod]
@ -247,7 +247,7 @@ namespace ViewModelTests
var mockSettingsUtils = ISettingsUtilsMocks.GetStubSettingsUtils<ImageResizerSettings>();
Func<string, int> sendMockIPCConfigMSG = msg => { return 0; };
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;
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);
// act
viewModel.AddRow("New size"); // Add: "New size 1"
viewModel.AddRow("New size"); // Add: "New size 2"
viewModel.AddRow("New size"); // Add: "New size 3"
viewModel.AddImageSize("New size"); // Add: "New size 1"
viewModel.AddImageSize("New size"); // Add: "New size 2"
viewModel.AddImageSize("New size"); // Add: "New size 3"
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.AreEqual(viewModel.Sizes[0].Name, "New size 1");
Assert.AreEqual(viewModel.Sizes[1].Name, "New size 3");
Assert.AreEqual(viewModel.Sizes[2].Name, "New size 4");
Assert.AreEqual("New size 1", viewModel.Sizes[0].Name);
Assert.AreEqual("New size 3", viewModel.Sizes[1].Name);
Assert.AreEqual("New size 4", viewModel.Sizes[2].Name);
}
[TestMethod]

Просмотреть файл

@ -3,41 +3,38 @@
// 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
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;
if ((string)parameter == "ToLower")
{
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;
return parameter is string lowerParam && lowerParam == "ToLower" ?
fitText.ToLower(CultureInfo.CurrentCulture) :
fitText;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return value;
}
return DependencyProperty.UnsetValue;
}
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.
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
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;
if ((string)parameter == "ToLower")
{
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;
return parameter is string lowerParam && lowerParam == "ToLower" ?
unitText.ToLower(CultureInfo.CurrentCulture) :
unitText;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return value;
}
return DependencyProperty.UnsetValue;
}
public object ConvertBack(object value, Type targetType, object parameter, string language)
{
return value;
}
}

Просмотреть файл

@ -18,6 +18,7 @@
<converters:ImageResizerFitToIntConverter x:Key="ImageResizerFitToIntConverter" />
<converters:ImageResizerUnitToStringConverter x:Key="ImageResizerUnitToStringConverter" />
<converters:ImageResizerUnitToIntConverter x:Key="ImageResizerUnitToIntConverter" />
<converters:ImageResizerSizeToAccessibleTextConverter x:Key="ImageResizerSizeToAccessibleTextConverter" />
<toolkitconverters:BoolToObjectConverter
x:Key="BoolToComboBoxIndexConverter"
FalseValue="1"
@ -85,13 +86,13 @@
FontSize="10"
Style="{ThemeResource SecondaryTextStyle}"
Text="&#xE947;"
Visibility="{x:Bind EnableEtraBoxes, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
Visibility="{x:Bind IsHeightUsed, Mode=OneWay, Converter={StaticResource BoolToVisibilityConverter}}" />
<TextBlock
Margin="0,0,4,0"
FontWeight="SemiBold"
Style="{ThemeResource SecondaryTextStyle}"
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
Margin="0,0,4,0"
Style="{ThemeResource SecondaryTextStyle}"
@ -104,9 +105,11 @@
Orientation="Horizontal"
Spacing="8">
<Button
x:Uid="EditButton"
x:Uid="ImageResizer_EditButton"
Width="40"
Height="36"
AutomationProperties.FullDescription="{x:Bind AccessibleTextHelper, Mode=OneWay, Converter={StaticResource ImageResizerSizeToAccessibleTextConverter}, ConverterParameter='Edit'}"
AutomationProperties.Name="{x:Bind Name, Mode=OneWay, Converter={StaticResource ImageResizerSizeToAccessibleTextConverter}, ConverterParameter='Edit'}"
Content="&#xE70F;"
FontFamily="{ThemeResource SymbolThemeFontFamily}"
Style="{StaticResource SubtleButtonStyle}">
@ -145,10 +148,10 @@
Width="116"
Minimum="0"
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}" />
</StackPanel>
<ComboBox
x:Uid="ImageResizer_Size"
Width="240"
@ -164,10 +167,11 @@
</Button>
<Button
x:Name="RemoveButton"
x:Uid="RemoveButton"
x:Uid="ImageResizer_RemoveButton"
Width="40"
Height="36"
AutomationProperties.FullDescription="{x:Bind AccessibleTextHelper, Mode=OneWay, Converter={StaticResource ImageResizerSizeToAccessibleTextConverter}, ConverterParameter='Remove'}"
AutomationProperties.Name="{x:Bind Name, Mode=OneWay, Converter={StaticResource ImageResizerSizeToAccessibleTextConverter}, ConverterParameter='Remove'}"
Click="DeleteCustomSize"
CommandParameter="{Binding Id}"
Content="&#xE74D;"

Просмотреть файл

@ -22,11 +22,8 @@ namespace Microsoft.PowerToys.Settings.UI.Views
{
InitializeComponent();
var settingsUtils = new SettingsUtils();
var resourceLoader = Helpers.ResourceLoaderInstance.ResourceLoader;
Func<string, string> loader = (string name) =>
{
return resourceLoader.GetString(name);
};
var resourceLoader = ResourceLoaderInstance.ResourceLoader;
Func<string, string> loader = resourceLoader.GetString;
ViewModel = new ImageResizerViewModel(settingsUtils, SettingsRepository<GeneralSettings>.GetInstance(settingsUtils), ShellPage.SendDefaultIPCMessage, loader);
DataContext = ViewModel;
@ -69,7 +66,7 @@ namespace Microsoft.PowerToys.Settings.UI.Views
{
try
{
ViewModel.AddRow(Helpers.ResourceLoaderInstance.ResourceLoader.GetString("ImageResizer_DefaultSize_NewSizePrefix"));
ViewModel.AddImageSize();
}
catch (Exception ex)
{

Просмотреть файл

@ -879,7 +879,7 @@
<value>Location</value>
</data>
<data name="General_SettingsBackupAndRestore_ButtonBackup.Content" xml:space="preserve">
<value>Backup</value>
<value>Back up</value>
</data>
<data name="General_SettingsBackupInfo_FileNameHeader.Text" xml:space="preserve">
<value>File name:</value>
@ -1104,10 +1104,10 @@
<value>Appearance &amp; behavior</value>
</data>
<data name="General_SettingsBackupAndRestoreTitle.Header" xml:space="preserve">
<value>Backup &amp; restore</value>
<value>Back up &amp; restore</value>
</data>
<data name="General_SettingsBackupAndRestore.Header" xml:space="preserve">
<value>Backup and restore your settings</value>
<value>Back up and restore your settings</value>
</data>
<data name="General_SettingsBackupAndRestore.Description" xml:space="preserve">
<value>PowerToys will restart automatically if needed</value>
@ -1169,10 +1169,6 @@
<data name="ImageResizer_Size.Header" xml:space="preserve">
<value>Unit</value>
</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">
<value>Delete</value>
</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">
<value>Pixels</value>
</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>
</data>
<data name="ImageResizer_EditSize.[using:Microsoft.UI.Xaml.Automation]AutomationProperties.Name" xml:space="preserve">
<value>Edit size</value>
</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">
<value>No</value>
<comment>Label of a cancel button</comment>
@ -3330,7 +3343,7 @@ Activate by holding the key for the character you want to add an accent to, then
<value>There was an error in the settings format. Please check the settings file:</value>
</data>
<data name="General_SettingsBackupAndRestore_BackupComplete" xml:space="preserve">
<value>Backup completed.</value>
<value>Back up completed.</value>
</data>
<data name="General_SettingsBackupAndRestore_NoBackupSyncPath" xml:space="preserve">
<value>No backup location selected.</value>
@ -4375,7 +4388,7 @@ Activate by holding the key for the character you want to add an accent to, then
<comment>Localize product name in accordance with Windows New</comment>
</data>
<data name="NewPlus_TemplatesNotBackupAndRestoreWarning.Title" xml:space="preserve">
<value>PowerToys "Backup and Restore" feature doesn't take templates into account at this moment. If you use that feature, templates will have to be copied manually.</value>
<value>PowerToys "Back up and Restore" feature doesn't take templates into account at this moment. If you use that feature, templates will have to be copied manually.</value>
</data>
<data name="NewPlus_Templates.Header" xml:space="preserve">
<value>Templates</value>

Просмотреть файл

@ -3,431 +3,362 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Runtime.CompilerServices;
using global::PowerToys.GPOWrapper;
using ManagedCommon;
using Microsoft.PowerToys.Settings.UI.Library;
using Microsoft.PowerToys.Settings.UI.Library.Helpers;
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; }
public ImageResizerViewModel(ISettingsUtils settingsUtils, ISettingsRepository<GeneralSettings> settingsRepository, Func<string, int> ipcMSGCallBackFunc, Func<string, string> resourceLoader)
try
{
_settingsUtils = settingsUtils ?? throw new ArgumentNullException(nameof(settingsUtils));
// To obtain the general settings configurations of PowerToys.
ArgumentNullException.ThrowIfNull(settingsRepository);
GeneralSettingsConfig = settingsRepository.SettingsConfig;
try
{
Settings = _settingsUtils.GetSettings<ImageResizerSettings>(ModuleName);
}
catch (Exception e)
{
Logger.LogError($"Exception encountered while reading {ModuleName} settings.", e);
Settings = _settingsUtils.GetSettings<ImageResizerSettings>(ModuleName);
}
catch (Exception e)
{
Logger.LogError($"Exception encountered while reading {ModuleName} settings.", e);
#if DEBUG
if (e is ArgumentException || e is ArgumentNullException || e is PathTooLongException)
{
throw;
}
if (e is ArgumentException || e is ArgumentNullException || e is PathTooLongException)
{
throw;
}
#endif
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);
Settings = new ImageResizerSettings(resourceLoader);
_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
if (value == 0)
{
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;
// Get the enabled state from GPO.
_enabledStateIsGPOConfigured = true;
_isEnabled = _enabledGpoRuleConfiguration == GpoRuleConfigured.Enabled;
}
public static int GetEncoderIndex(string value)
else
{
// PNG Encoder guid
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));
_isEnabled = GeneralSettingsConfig.Enabled.ImageResizer;
}
}
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));
}
}