mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-05 18:57:19 +02:00
Merge branch 'master' into spelling
This commit is contained in:
@@ -69,6 +69,7 @@
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.IO.Abstractions" Version="12.2.5" />
|
||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||
<PackageReference Include="xunit" Version="2.4.1" />
|
||||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
|
||||
@@ -170,6 +170,7 @@ namespace ImageResizer.Properties
|
||||
|
||||
var result = ((IDataErrorInfo)settings)["JpegQualityLevel"];
|
||||
|
||||
// Using InvariantCulture since this is used internally
|
||||
Assert.Equal(
|
||||
string.Format(CultureInfo.InvariantCulture, Resources.ValueMustBeBetween, 1, 100),
|
||||
result);
|
||||
|
||||
@@ -6,7 +6,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Xunit;
|
||||
|
||||
@@ -14,6 +14,8 @@ namespace ImageResizer.Test
|
||||
{
|
||||
internal static class AssertEx
|
||||
{
|
||||
private static readonly IFileSystem _fileSystem = new FileSystem();
|
||||
|
||||
public static void All<T>(IEnumerable<T> collection, Action<T> action)
|
||||
{
|
||||
foreach (var item in collection)
|
||||
@@ -24,7 +26,7 @@ namespace ImageResizer.Test
|
||||
|
||||
public static void Image(string path, Action<BitmapDecoder> action)
|
||||
{
|
||||
using (var stream = File.OpenRead(path))
|
||||
using (var stream = _fileSystem.File.OpenRead(path))
|
||||
{
|
||||
var image = BitmapDecoder.Create(
|
||||
stream,
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace ImageResizer.Views
|
||||
var timeRemaining = new TimeSpan(hours, minutes, seconds);
|
||||
var converter = new TimeRemainingConverter();
|
||||
|
||||
// Using InvariantCulture since these are internal
|
||||
var result = converter.Convert(
|
||||
timeRemaining,
|
||||
targetType: null,
|
||||
|
||||
@@ -69,6 +69,9 @@
|
||||
<PackageReference Include="StyleCop.Analyzers" Version="1.1.118">
|
||||
<PrivateAssets>all</PrivateAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="System.IO.Abstractions">
|
||||
<Version>12.2.5</Version>
|
||||
</PackageReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\..\common\interop\interop.vcxproj" />
|
||||
|
||||
@@ -6,6 +6,7 @@ using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using ImageResizer.Properties;
|
||||
@@ -14,6 +15,8 @@ namespace ImageResizer.Models
|
||||
{
|
||||
public class ResizeBatch
|
||||
{
|
||||
private readonly IFileSystem _fileSystem = new FileSystem();
|
||||
|
||||
public string DestinationDirectory { get; set; }
|
||||
|
||||
public ICollection<string> Files { get; } = new List<string>();
|
||||
@@ -71,7 +74,7 @@ namespace ImageResizer.Models
|
||||
catch (Exception ex)
|
||||
#pragma warning restore CA1031 // Do not catch general exception types
|
||||
{
|
||||
errors.Add(new ResizeError { File = Path.GetFileName(file), Error = ex.Message });
|
||||
errors.Add(new ResizeError { File = _fileSystem.Path.GetFileName(file), Error = ex.Message });
|
||||
}
|
||||
|
||||
Interlocked.Increment(ref completed);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
@@ -12,11 +13,14 @@ using System.Windows.Media.Imaging;
|
||||
using ImageResizer.Properties;
|
||||
using ImageResizer.Utilities;
|
||||
using Microsoft.VisualBasic.FileIO;
|
||||
using FileSystem = Microsoft.VisualBasic.FileIO.FileSystem;
|
||||
|
||||
namespace ImageResizer.Models
|
||||
{
|
||||
internal class ResizeOperation
|
||||
{
|
||||
private readonly IFileSystem _fileSystem = new System.IO.Abstractions.FileSystem();
|
||||
|
||||
private readonly string _file;
|
||||
private readonly string _destinationDirectory;
|
||||
private readonly Settings _settings;
|
||||
@@ -31,7 +35,7 @@ namespace ImageResizer.Models
|
||||
public void Execute()
|
||||
{
|
||||
string path;
|
||||
using (var inputStream = File.OpenRead(_file))
|
||||
using (var inputStream = _fileSystem.File.OpenRead(_file))
|
||||
{
|
||||
var decoder = BitmapDecoder.Create(
|
||||
inputStream,
|
||||
@@ -87,8 +91,8 @@ namespace ImageResizer.Models
|
||||
}
|
||||
|
||||
path = GetDestinationPath(encoder);
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(path));
|
||||
using (var outputStream = File.Open(path, FileMode.CreateNew, FileAccess.Write))
|
||||
_fileSystem.Directory.CreateDirectory(_fileSystem.Path.GetDirectoryName(path));
|
||||
using (var outputStream = _fileSystem.File.Open(path, FileMode.CreateNew, FileAccess.Write))
|
||||
{
|
||||
encoder.Save(outputStream);
|
||||
}
|
||||
@@ -96,13 +100,13 @@ namespace ImageResizer.Models
|
||||
|
||||
if (_settings.KeepDateModified)
|
||||
{
|
||||
File.SetLastWriteTimeUtc(path, File.GetLastWriteTimeUtc(_file));
|
||||
_fileSystem.File.SetLastWriteTimeUtc(path, _fileSystem.File.GetLastWriteTimeUtc(_file));
|
||||
}
|
||||
|
||||
if (_settings.Replace)
|
||||
{
|
||||
var backup = GetBackupPath();
|
||||
File.Replace(path, _file, backup, ignoreMetadataErrors: true);
|
||||
_fileSystem.File.Replace(path, _file, backup, ignoreMetadataErrors: true);
|
||||
FileSystem.DeleteFile(backup, UIOption.OnlyErrorDialogs, RecycleOption.SendToRecycleBin);
|
||||
}
|
||||
}
|
||||
@@ -179,16 +183,17 @@ namespace ImageResizer.Models
|
||||
|
||||
private string GetDestinationPath(BitmapEncoder encoder)
|
||||
{
|
||||
var directory = _destinationDirectory ?? Path.GetDirectoryName(_file);
|
||||
var originalFileName = Path.GetFileNameWithoutExtension(_file);
|
||||
var directory = _destinationDirectory ?? _fileSystem.Path.GetDirectoryName(_file);
|
||||
var originalFileName = _fileSystem.Path.GetFileNameWithoutExtension(_file);
|
||||
|
||||
var supportedExtensions = encoder.CodecInfo.FileExtensions.Split(',');
|
||||
var extension = Path.GetExtension(_file);
|
||||
var extension = _fileSystem.Path.GetExtension(_file);
|
||||
if (!supportedExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase))
|
||||
{
|
||||
extension = supportedExtensions.FirstOrDefault();
|
||||
}
|
||||
|
||||
// Using CurrentCulture since this is user facing
|
||||
var fileName = string.Format(
|
||||
CultureInfo.CurrentCulture,
|
||||
_settings.FileNameFormat,
|
||||
@@ -198,11 +203,11 @@ namespace ImageResizer.Models
|
||||
_settings.SelectedSize.Height,
|
||||
encoder.Frames[0].PixelWidth,
|
||||
encoder.Frames[0].PixelHeight);
|
||||
var path = Path.Combine(directory, fileName + extension);
|
||||
var path = _fileSystem.Path.Combine(directory, fileName + extension);
|
||||
var uniquifier = 1;
|
||||
while (File.Exists(path))
|
||||
while (_fileSystem.File.Exists(path))
|
||||
{
|
||||
path = Path.Combine(directory, fileName + " (" + uniquifier++ + ")" + extension);
|
||||
path = _fileSystem.Path.Combine(directory, fileName + " (" + uniquifier++ + ")" + extension);
|
||||
}
|
||||
|
||||
return path;
|
||||
@@ -210,15 +215,15 @@ namespace ImageResizer.Models
|
||||
|
||||
private string GetBackupPath()
|
||||
{
|
||||
var directory = Path.GetDirectoryName(_file);
|
||||
var fileName = Path.GetFileNameWithoutExtension(_file);
|
||||
var extension = Path.GetExtension(_file);
|
||||
var directory = _fileSystem.Path.GetDirectoryName(_file);
|
||||
var fileName = _fileSystem.Path.GetFileNameWithoutExtension(_file);
|
||||
var extension = _fileSystem.Path.GetExtension(_file);
|
||||
|
||||
var path = Path.Combine(directory, fileName + ".bak" + extension);
|
||||
var path = _fileSystem.Path.Combine(directory, fileName + ".bak" + extension);
|
||||
var uniquifier = 1;
|
||||
while (File.Exists(path))
|
||||
while (_fileSystem.File.Exists(path))
|
||||
{
|
||||
path = Path.Combine(directory, fileName + " (" + uniquifier++ + ")" + ".bak" + extension);
|
||||
path = _fileSystem.Path.Combine(directory, fileName + " (" + uniquifier++ + ")" + ".bak" + extension);
|
||||
}
|
||||
|
||||
return path;
|
||||
|
||||
@@ -9,7 +9,7 @@ using System.Collections.ObjectModel;
|
||||
using System.Collections.Specialized;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.IO.Abstractions;
|
||||
using System.Threading;
|
||||
using System.Windows.Media.Imaging;
|
||||
using ImageResizer.Models;
|
||||
@@ -22,9 +22,11 @@ namespace ImageResizer.Properties
|
||||
[JsonObject(MemberSerialization.OptIn)]
|
||||
public sealed partial class Settings : IDataErrorInfo, INotifyPropertyChanged
|
||||
{
|
||||
private static readonly IFileSystem _fileSystem = new FileSystem();
|
||||
|
||||
// Used to synchronize access to the settings.json file
|
||||
private static Mutex _jsonMutex = new Mutex();
|
||||
private static string _settingsPath = Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData), "Microsoft", "PowerToys", "ImageResizer", "settings.json");
|
||||
private static string _settingsPath = _fileSystem.Path.Combine(System.Environment.GetFolderPath(System.Environment.SpecialFolder.LocalApplicationData), "Microsoft", "PowerToys", "ImageResizer", "settings.json");
|
||||
private string _fileNameFormat;
|
||||
private bool _shrinkOnly;
|
||||
private int _selectedSizeIndex;
|
||||
@@ -63,6 +65,7 @@ namespace ImageResizer.Properties
|
||||
|
||||
public IEnumerable<ResizeSize> AllSizes { get; set; }
|
||||
|
||||
// Using OrdinalIgnoreCase since this is internal and used for comparison with symbols
|
||||
public string FileNameFormat
|
||||
=> _fileNameFormat
|
||||
?? (_fileNameFormat = FileName
|
||||
@@ -111,6 +114,7 @@ namespace ImageResizer.Properties
|
||||
|
||||
if (JpegQualityLevel < 1 || JpegQualityLevel > 100)
|
||||
{
|
||||
// Using CurrentCulture since this is user facing
|
||||
return string.Format(CultureInfo.CurrentCulture, Resources.ValueMustBeBetween, 1, 100);
|
||||
}
|
||||
|
||||
@@ -382,25 +386,25 @@ namespace ImageResizer.Properties
|
||||
jsonData += "}";
|
||||
|
||||
// Create directory if it doesn't exist
|
||||
FileInfo file = new FileInfo(SettingsPath);
|
||||
IFileInfo file = _fileSystem.FileInfo.FromFileName(SettingsPath);
|
||||
file.Directory.Create();
|
||||
|
||||
// write string to file
|
||||
File.WriteAllText(SettingsPath, jsonData);
|
||||
_fileSystem.File.WriteAllText(SettingsPath, jsonData);
|
||||
_jsonMutex.ReleaseMutex();
|
||||
}
|
||||
|
||||
public void Reload()
|
||||
{
|
||||
_jsonMutex.WaitOne();
|
||||
if (!File.Exists(SettingsPath))
|
||||
if (!_fileSystem.File.Exists(SettingsPath))
|
||||
{
|
||||
_jsonMutex.ReleaseMutex();
|
||||
Save();
|
||||
return;
|
||||
}
|
||||
|
||||
string jsonData = File.ReadAllText(SettingsPath);
|
||||
string jsonData = _fileSystem.File.ReadAllText(SettingsPath);
|
||||
JObject imageResizerSettings = JObject.Parse(jsonData);
|
||||
|
||||
// Replace the { "value": <Value> } with <Value> to match the Settings object format
|
||||
|
||||
24
src/modules/imageresizer/ui/Views/AccessibleHyperlink.cs
Normal file
24
src/modules/imageresizer/ui/Views/AccessibleHyperlink.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
// 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.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Automation.Peers;
|
||||
using System.Windows.Documents;
|
||||
|
||||
namespace ImageResizer.Views
|
||||
{
|
||||
public class AccessibleHyperlink : Hyperlink
|
||||
{
|
||||
public AutomationControlType ControlType { get; set; }
|
||||
|
||||
protected override AutomationPeer OnCreateAutomationPeer()
|
||||
{
|
||||
var peer = new CustomizableHyperlinkAutomationPeer(this);
|
||||
|
||||
peer.ControlType = ControlType;
|
||||
return peer;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -114,18 +114,18 @@
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
<TextBlock Grid.Column="6" Margin="5,0,0,0" VerticalAlignment="Center">
|
||||
<Hyperlink Command="{Binding DataContext.RemoveSizeCommand,ElementName=_this}" CommandParameter="{Binding}">
|
||||
<local:AccessibleHyperlink ControlType="Button" Command="{Binding DataContext.RemoveSizeCommand,ElementName=_this}" CommandParameter="{Binding}">
|
||||
<Run Text="{x:Static p:Resources.Advanced_DeleteSize}"/>
|
||||
</Hyperlink>
|
||||
</local:AccessibleHyperlink>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<TextBlock>
|
||||
<Hyperlink Command="{Binding AddSizeCommand}">
|
||||
<local:AccessibleHyperlink ControlType="Button" Command="{Binding AddSizeCommand}">
|
||||
<Run Text="{x:Static p:Resources.Advanced_CreateSize}"/>
|
||||
</Hyperlink>
|
||||
</local:AccessibleHyperlink>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</TabItem>
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// 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.Windows.Automation.Peers;
|
||||
using System.Windows.Documents;
|
||||
|
||||
namespace ImageResizer.Views
|
||||
{
|
||||
public class CustomizableHyperlinkAutomationPeer : HyperlinkAutomationPeer
|
||||
{
|
||||
public CustomizableHyperlinkAutomationPeer(Hyperlink owner)
|
||||
: base(owner)
|
||||
{
|
||||
}
|
||||
|
||||
public AutomationControlType ControlType { get; set; }
|
||||
|
||||
protected override AutomationControlType GetAutomationControlTypeCore()
|
||||
{
|
||||
return ControlType;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -133,9 +133,9 @@
|
||||
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Visibility="{Binding ShowAdvancedSettings, Converter={StaticResource BoolValueConverter}}">
|
||||
<Hyperlink Command="{Binding ShowAdvancedCommand}">
|
||||
<local:AccessibleHyperlink ControlType="Button" Command="{Binding ShowAdvancedCommand}">
|
||||
<Run Text="{x:Static p:Resources.Input_ShowAdvanced}"/>
|
||||
</Hyperlink>
|
||||
</local:AccessibleHyperlink>
|
||||
</TextBlock>
|
||||
|
||||
<Button Grid.Column="1"
|
||||
|
||||
Reference in New Issue
Block a user