Merge branch 'master' into dev/crutkas/upgradeNuget

This commit is contained in:
Clint Rutkas
2020-11-03 10:57:50 -08:00
committed by GitHub
432 changed files with 7397 additions and 3096 deletions

View File

@@ -14,7 +14,7 @@
<Str Cat="Text">
<Val><![CDATA[Image Resizer]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[像大小調整器]]></Val>
<Val><![CDATA[像大小調整器]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@@ -50,7 +50,7 @@
<Str Cat="Text">
<Val><![CDATA[Settings can be accessed from within Image Resizer.]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[這些設定可以從像大小調整器中存取。]]></Val>
<Val><![CDATA[這些設定可以從像大小調整器中存取。]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@@ -59,7 +59,7 @@
<Str Cat="Text">
<Val><![CDATA[Settings header for Image Resizer]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[像大小調整器的設定標題]]></Val>
<Val><![CDATA[像大小調整器的設定標題]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />

View File

@@ -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">

View File

@@ -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;

View File

@@ -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);

View File

@@ -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,

View File

@@ -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,

View File

@@ -23,13 +23,54 @@
<v:EnumValueConverter x:Key="EnumValueConverter"/>
<v:AutoDoubleConverter x:Key="AutoDoubleConverter"/>
<v:BoolValueConverter x:Key="BoolValueConverter"/>
<v:VisibilityBoolConverter x:Key="VisibilityBoolConverter"/>
<Style x:Key="MainInstructionTextBlockStyle" TargetType="TextBlock">
<Setter Property="FontSize" Value="12pt"/>
<Setter Property="Foreground" Value="#039"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HotTrackColor}}"/>
</Style>
<Style TargetType="TextBox">
<Setter Property="VerticalContentAlignment" Value="Center"/>
</Style>
<Style x:Key="AccessibleComboBoxStyle" TargetType="ComboBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ComboBoxItem}">
<Border Name="SelectedItemBorder"
Padding="2"
SnapsToDevicePixels="true">
<ContentPresenter />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="true">
<Setter TargetName="SelectedItemBorder"
Property="Background"
Value="#FF91b9d8"/>
<Setter Property="Foreground"
Value="Black" />
</Trigger>
<Trigger Property="IsHighlighted" Value="true">
<Setter TargetName="SelectedItemBorder"
Property="Background"
Value="#FFdadada" />
<Setter Property="Foreground"
Value="Black" />
</Trigger>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true" />
<Condition Property="IsHighlighted" Value="true" />
</MultiTrigger.Conditions>
<Setter TargetName="SelectedItemBorder"
Property="Background"
Value="#FF619ccb"/>
<Setter Property="Foreground"
Value="Black" />
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Application.Resources>
</Application>

View File

@@ -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" />

View File

@@ -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);

View File

@@ -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;

View File

@@ -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

View 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;
}
}
}

View File

@@ -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>

View File

@@ -16,6 +16,6 @@ namespace ImageResizer.Views
=> (bool)value ? Visibility.Visible : Visibility.Collapsed;
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> throw new NotImplementedException();
=> (Visibility)value == Visibility.Visible;
}
}

View 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.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;
}
}
}

View File

@@ -55,7 +55,8 @@
<ComboBox Height="23"
Margin="5,0,0,0"
ItemsSource="{Binding Source={StaticResource ResizeFitValues}}"
SelectedItem="{Binding Fit}">
SelectedItem="{Binding Fit}"
ItemContainerStyle="{StaticResource AccessibleComboBoxStyle}">
<ComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type m:ResizeFit}">
<ContentPresenter Content="{Binding Converter={StaticResource EnumValueConverter}}"/>
@@ -97,7 +98,8 @@
<ComboBox Height="23"
Margin="7,0,0,0"
ItemsSource="{Binding Source={StaticResource ResizeUnitValues}}"
SelectedItem="{Binding Unit}">
SelectedItem="{Binding Unit}"
ItemContainerStyle="{StaticResource AccessibleComboBoxStyle}">
<ComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type m:ResizeUnit}">
<ContentPresenter Content="{Binding Converter={StaticResource EnumValueConverter}}"/>
@@ -130,12 +132,15 @@
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock VerticalAlignment="Center"
Visibility="{Binding ShowAdvancedSettings, Converter={StaticResource BoolValueConverter}}">
<Hyperlink Command="{Binding ShowAdvancedCommand}">
<TextBlock x:Name="AdvancedSettingsTextBlock"
VerticalAlignment="Center"
Visibility="{Binding ShowAdvancedSettings, Converter={StaticResource BoolValueConverter}}"
IsEnabled="{Binding Visibility,ElementName=AdvancedSettingsTextBlock, Converter={StaticResource VisibilityBoolConverter}}"
Focusable="{Binding Visibility,ElementName=AdvancedSettingsTextBlock, Converter={StaticResource VisibilityBoolConverter}}">
<local:AccessibleHyperlink ControlType="Button" Command="{Binding ShowAdvancedCommand}">
<Run Text="{x:Static p:Resources.Input_ShowAdvanced}"/>
</Hyperlink>
</local:AccessibleHyperlink>
</TextBlock>
<Button Grid.Column="1"

View File

@@ -0,0 +1,21 @@
// Copyright (c) Brice Lambson
// The Brice Lambson licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information. Code forked from Brice Lambson's https://github.com/bricelam/ImageResizer/
using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
namespace ImageResizer.Views
{
[ValueConversion(typeof(Visibility), typeof(bool))]
internal class VisibilityBoolConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
=> (Visibility)value == Visibility.Visible;
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> (bool)value ? Visibility.Visible : Visibility.Collapsed;
}
}

View File

@@ -500,7 +500,7 @@
<Str Cat="Text">
<Val><![CDATA[fills]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[rellena]]></Val>
<Val><![CDATA[llena]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />

View File

@@ -491,7 +491,7 @@
<Str Cat="Text">
<Val><![CDATA[Fill]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[채우기]]></Val>
<Val><![CDATA[늘이기]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@@ -500,7 +500,7 @@
<Str Cat="Text">
<Val><![CDATA[fills]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[채우기]]></Val>
<Val><![CDATA[늘이기]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />

View File

@@ -527,7 +527,7 @@
<Str Cat="Text">
<Val><![CDATA[Stretch]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[Spreiden]]></Val>
<Val><![CDATA[Uitrekken]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@@ -536,7 +536,7 @@
<Str Cat="Text">
<Val><![CDATA[stretches to]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[strekt zich uit tot]]></Val>
<Val><![CDATA[uitgerekt tot]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />

View File

@@ -221,7 +221,7 @@
<Str Cat="Text">
<Val><![CDATA[Image Resizer]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[像大小調整器]]></Val>
<Val><![CDATA[像大小調整器]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />
@@ -518,7 +518,7 @@
<Str Cat="Text">
<Val><![CDATA[fits within]]></Val>
<Tgt Cat="Text" Stat="Loc" Orig="New">
<Val><![CDATA[調整大小]]></Val>
<Val><![CDATA[最適大小]]></Val>
</Tgt>
</Str>
<Disp Icon="Str" />