diff --git a/src/dev/impl/DevToys/Api/Core/Settings/SettingDefinition.cs b/src/dev/impl/DevToys/Api/Core/Settings/SettingDefinition.cs
index 6222f5351d..ea7192f921 100644
--- a/src/dev/impl/DevToys/Api/Core/Settings/SettingDefinition.cs
+++ b/src/dev/impl/DevToys/Api/Core/Settings/SettingDefinition.cs
@@ -33,6 +33,13 @@ namespace DevToys.Api.Core.Settings
/// The default value of the setting.
public SettingDefinition(string name, bool isRoaming, T defaultValue)
{
+ if (string.IsNullOrEmpty(name) || name.Length > 255)
+ {
+ // For both LocalSettings and RoamingSettings, the name of each setting can be 255 characters in length at most.
+ // see https://docs.microsoft.com/en-us/uwp/api/windows.storage.applicationdata.localsettings?view=winrt-22000#remarks
+ throw new ArgumentOutOfRangeException(nameof(name));
+ }
+
IsRoaming = isRoaming;
Name = name;
DefaultValue = defaultValue;
diff --git a/src/dev/impl/DevToys/ViewModels/Tools/Base64EncoderDecoder/Base64EncoderDecoderToolViewModel.cs b/src/dev/impl/DevToys/ViewModels/Tools/Base64EncoderDecoder/Base64EncoderDecoderToolViewModel.cs
index 92d738d5f0..bb796905f2 100644
--- a/src/dev/impl/DevToys/ViewModels/Tools/Base64EncoderDecoder/Base64EncoderDecoderToolViewModel.cs
+++ b/src/dev/impl/DevToys/ViewModels/Tools/Base64EncoderDecoder/Base64EncoderDecoderToolViewModel.cs
@@ -1,5 +1,6 @@
#nullable enable
+using DevToys.Api.Core.Settings;
using DevToys.Api.Tools;
using DevToys.Core;
using DevToys.Core.Threading;
@@ -16,17 +17,35 @@ namespace DevToys.ViewModels.Tools.Base64EncoderDecoder
[Export(typeof(Base64EncoderDecoderToolViewModel))]
public class Base64EncoderDecoderToolViewModel : ObservableRecipient, IToolViewModel
{
+ ///
+ /// Whether the tool should encode or decode Base64.
+ ///
+ private static readonly SettingDefinition Conversion
+ = new(
+ name: $"{nameof(Base64EncoderDecoderToolViewModel)}.{nameof(Conversion)}",
+ isRoaming: true,
+ defaultValue: DefaultConversion);
+
+ ///
+ /// Whether the tool should encode/decode in Unicode or ASCII.
+ ///
+ private static readonly SettingDefinition Encoder
+ = new(
+ name: $"{nameof(Base64EncoderDecoderToolViewModel)}.{nameof(Encoder)}",
+ isRoaming: true,
+ defaultValue: DefaultEncoding);
+
private const string DefaultEncoding = "UTF-8";
private const string DefaultConversion = "Encode";
internal const string DecodeConversion = "Decode";
+ private readonly ISettingsProvider _settingsProvider;
+ private readonly Queue _conversionQueue = new();
+
private string? _inputValue;
private string? _outputValue;
- private string _encodingMode = DefaultEncoding;
- private string _conversionMode = DefaultConversion;
private bool _conversionInProgress;
private bool _setPropertyInProgress;
- private readonly Queue _conversionQueue = new();
public Type View { get; } = typeof(Base64EncoderDecoderToolPage);
@@ -60,14 +79,18 @@ internal string? OutputValue
///
internal string ConversionMode
{
- get => _conversionMode;
+ get => _settingsProvider.GetSetting(Conversion);
set
{
if (!_setPropertyInProgress)
{
_setPropertyInProgress = true;
ThreadHelper.ThrowIfNotOnUIThread();
- SetProperty(ref _conversionMode, value);
+ if (!string.Equals(_settingsProvider.GetSetting(Conversion), value, StringComparison.Ordinal))
+ {
+ _settingsProvider.SetSetting(Conversion, value);
+ OnPropertyChanged();
+ }
InputValue = OutputValue;
_setPropertyInProgress = false;
}
@@ -79,15 +102,25 @@ internal string ConversionMode
///
internal string EncodingMode
{
- get => _encodingMode;
+ get => _settingsProvider.GetSetting(Encoder);
set
{
ThreadHelper.ThrowIfNotOnUIThread();
- SetProperty(ref _encodingMode, value);
- QueueConversionCalculation();
+ if (!string.Equals(_settingsProvider.GetSetting(Encoder), value, StringComparison.Ordinal))
+ {
+ _settingsProvider.SetSetting(Encoder, value);
+ OnPropertyChanged();
+ QueueConversionCalculation();
+ }
}
}
+ [ImportingConstructor]
+ public Base64EncoderDecoderToolViewModel(ISettingsProvider settingsProvider)
+ {
+ _settingsProvider = settingsProvider;
+ }
+
private void QueueConversionCalculation()
{
_conversionQueue.Enqueue(InputValue ?? string.Empty);
diff --git a/src/dev/impl/DevToys/ViewModels/Tools/HashGenerator/HashGeneratorToolViewModel.cs b/src/dev/impl/DevToys/ViewModels/Tools/HashGenerator/HashGeneratorToolViewModel.cs
index 7a17679cbb..c656d98cea 100644
--- a/src/dev/impl/DevToys/ViewModels/Tools/HashGenerator/HashGeneratorToolViewModel.cs
+++ b/src/dev/impl/DevToys/ViewModels/Tools/HashGenerator/HashGeneratorToolViewModel.cs
@@ -1,5 +1,6 @@
#nullable enable
+using DevToys.Api.Core.Settings;
using DevToys.Api.Tools;
using DevToys.Core;
using DevToys.Core.Threading;
@@ -18,10 +19,19 @@ namespace DevToys.ViewModels.Tools.HashGenerator
[Export(typeof(HashGeneratorToolViewModel))]
public sealed class HashGeneratorToolViewModel : ObservableRecipient, IToolViewModel
{
+ ///
+ /// Whether the generated hash should be uppercase or lowercase.
+ ///
+ private static readonly SettingDefinition Uppercase
+ = new(
+ name: $"{nameof(HashGeneratorToolViewModel)}.{nameof(Uppercase)}",
+ isRoaming: true,
+ defaultValue: false);
+
+ private readonly ISettingsProvider _settingsProvider;
private readonly Queue _hashCalculationQueue = new();
private bool _calculationInProgress;
- private bool _isUppercase;
private string? _input;
private string? _md5;
private string? _sha1;
@@ -34,11 +44,15 @@ public sealed class HashGeneratorToolViewModel : ObservableRecipient, IToolViewM
internal bool IsUppercase
{
- get => _isUppercase;
+ get => _settingsProvider.GetSetting(Uppercase);
set
{
- SetProperty(ref _isUppercase, value);
- QueueHashCalculation();
+ if (_settingsProvider.GetSetting(Uppercase) != value)
+ {
+ _settingsProvider.SetSetting(Uppercase, value);
+ OnPropertyChanged();
+ QueueHashCalculation();
+ }
}
}
@@ -76,6 +90,12 @@ internal string? SHA512
private set => SetProperty(ref _sha512, value);
}
+ [ImportingConstructor]
+ public HashGeneratorToolViewModel(ISettingsProvider settingsProvider)
+ {
+ _settingsProvider = settingsProvider;
+ }
+
private void QueueHashCalculation()
{
_hashCalculationQueue.Enqueue(Input ?? string.Empty);
diff --git a/src/dev/impl/DevToys/ViewModels/Tools/JsonFormatter/JsonFormatterToolViewModel.cs b/src/dev/impl/DevToys/ViewModels/Tools/JsonFormatter/JsonFormatterToolViewModel.cs
index 305b9c0f44..841f8ad474 100644
--- a/src/dev/impl/DevToys/ViewModels/Tools/JsonFormatter/JsonFormatterToolViewModel.cs
+++ b/src/dev/impl/DevToys/ViewModels/Tools/JsonFormatter/JsonFormatterToolViewModel.cs
@@ -20,6 +20,15 @@ namespace DevToys.ViewModels.Tools.JsonFormatter
[Export(typeof(JsonFormatterToolViewModel))]
public sealed class JsonFormatterToolViewModel : ObservableRecipient, IToolViewModel
{
+ ///
+ /// The indentation to apply while formatting.
+ ///
+ private static readonly SettingDefinition Indentation
+ = new(
+ name: $"{nameof(JsonFormatterToolViewModel)}.{nameof(Indentation)}",
+ isRoaming: true,
+ defaultValue: TwoSpaceIndentation);
+
private const string TwoSpaceIndentation = "TwoSpaces";
private const string FourSpaceIndentation = "FourSpaces";
private const string OneTabIndentation = "OneTab";
@@ -30,7 +39,6 @@ public sealed class JsonFormatterToolViewModel : ObservableRecipient, IToolViewM
private bool _formattingInProgress;
private string? _inputValue;
private string? _outputValue;
- private string _indentation = TwoSpaceIndentation;
public Type View { get; } = typeof(JsonFormatterToolPage);
@@ -39,13 +47,17 @@ public sealed class JsonFormatterToolViewModel : ObservableRecipient, IToolViewM
///
/// Gets or sets the desired indentation.
///
- internal string Indentation
+ internal string IndentationMode
{
- get => _indentation;
+ get => SettingsProvider.GetSetting(Indentation);
set
{
- SetProperty(ref _indentation, value);
- QueueFormatting();
+ if (!string.Equals(SettingsProvider.GetSetting(Indentation), value, StringComparison.Ordinal))
+ {
+ SettingsProvider.SetSetting(Indentation, value);
+ OnPropertyChanged();
+ QueueFormatting();
+ }
}
}
@@ -124,7 +136,7 @@ private bool FormatJson(string input, out string output)
using (var stringWriter = new StringWriter(stringBuilder))
using (var jsonTextWriter = new JsonTextWriter(stringWriter))
{
- switch (Indentation)
+ switch (IndentationMode)
{
case TwoSpaceIndentation:
jsonTextWriter.Formatting = Formatting.Indented;
@@ -169,7 +181,7 @@ private bool FormatJson(string input, out string output)
}
catch (Exception ex) //some other exception
{
- Logger.LogFault("Json formatter", ex, $"Indentation: {Indentation}");
+ Logger.LogFault("Json formatter", ex, $"Indentation: {IndentationMode}");
output = ex.Message;
return false;
}
diff --git a/src/dev/impl/DevToys/ViewModels/Tools/JsonYaml/JsonYamlToolViewModel.cs b/src/dev/impl/DevToys/ViewModels/Tools/JsonYaml/JsonYamlToolViewModel.cs
index f9081dcfd0..ddb11e7fdb 100644
--- a/src/dev/impl/DevToys/ViewModels/Tools/JsonYaml/JsonYamlToolViewModel.cs
+++ b/src/dev/impl/DevToys/ViewModels/Tools/JsonYaml/JsonYamlToolViewModel.cs
@@ -23,6 +23,24 @@ namespace DevToys.ViewModels.Tools.JsonYaml
[Export(typeof(JsonYamlToolViewModel))]
public sealed class JsonYamlToolViewModel : ObservableRecipient, IToolViewModel
{
+ ///
+ /// Whether the tool should convert JSON to YAML or YAML to JSON.
+ ///
+ private static readonly SettingDefinition Conversion
+ = new(
+ name: $"{nameof(JsonYamlToolViewModel)}.{nameof(Conversion)}",
+ isRoaming: true,
+ defaultValue: JsonToYaml);
+
+ ///
+ /// The indentation to apply while converting.
+ ///
+ private static readonly SettingDefinition Indentation
+ = new(
+ name: $"{nameof(JsonYamlToolViewModel)}.{nameof(Indentation)}",
+ isRoaming: true,
+ defaultValue: TwoSpaceIndentation);
+
internal const string JsonToYaml = nameof(JsonToYaml);
internal const string YamlToJson = nameof(YamlToJson);
private const string TwoSpaceIndentation = "TwoSpaces";
@@ -36,8 +54,6 @@ public sealed class JsonYamlToolViewModel : ObservableRecipient, IToolViewModel
private string? _inputValueLanguage;
private string? _outputValue;
private string? _outputValueLanguage;
- private string _indentation = TwoSpaceIndentation;
- private string _conversionMode = JsonToYaml;
public Type View { get; } = typeof(JsonYamlToolPage);
@@ -48,34 +64,38 @@ public sealed class JsonYamlToolViewModel : ObservableRecipient, IToolViewModel
///
internal string ConversionMode
{
- get => _conversionMode;
+ get => SettingsProvider.GetSetting(Conversion);
set
{
if (!_setPropertyInProgress)
{
_setPropertyInProgress = true;
ThreadHelper.ThrowIfNotOnUIThread();
- SetProperty(ref _conversionMode, value);
-
- if (string.Equals(value, JsonToYaml))
+ if (!string.Equals(SettingsProvider.GetSetting(Conversion), value, StringComparison.Ordinal))
{
- if (JsonHelper.IsValidJson(OutputValue))
- {
- InputValue = OutputValue;
- }
+ SettingsProvider.SetSetting(Conversion, value);
+ OnPropertyChanged();
- InputValueLanguage = "json";
- OutputValueLanguage = "yaml";
- }
- else
- {
- if (YamlHelper.IsValidYaml(OutputValue))
+ if (string.Equals(value, JsonToYaml))
{
- InputValue = OutputValue;
+ if (JsonHelper.IsValidJson(OutputValue))
+ {
+ InputValue = OutputValue;
+ }
+
+ InputValueLanguage = "json";
+ OutputValueLanguage = "yaml";
}
+ else
+ {
+ if (YamlHelper.IsValidYaml(OutputValue))
+ {
+ InputValue = OutputValue;
+ }
- InputValueLanguage = "yaml";
- OutputValueLanguage = "json";
+ InputValueLanguage = "yaml";
+ OutputValueLanguage = "json";
+ }
}
_setPropertyInProgress = false;
@@ -86,13 +106,17 @@ internal string ConversionMode
///
/// Gets or sets the desired indentation.
///
- internal string Indentation
+ internal string IndentationMode
{
- get => _indentation;
+ get => SettingsProvider.GetSetting(Indentation);
set
{
- SetProperty(ref _indentation, value);
- QueueConversion();
+ if (!string.Equals(SettingsProvider.GetSetting(Indentation), value, StringComparison.Ordinal))
+ {
+ SettingsProvider.SetSetting(Indentation, value);
+ OnPropertyChanged();
+ QueueConversion();
+ }
}
}
@@ -199,7 +223,7 @@ private bool ConvertJsonToYaml(string input, out string output)
if (jsonObject is not null && jsonObject is not string)
{
int indent = 0;
- switch (Indentation)
+ switch (IndentationMode)
{
case TwoSpaceIndentation:
indent = 2;
@@ -263,7 +287,7 @@ private bool ConvertYamlToJson(string input, out string output)
using (var stringWriter = new StringWriter(stringBuilder))
using (var jsonTextWriter = new JsonTextWriter(stringWriter))
{
- switch (Indentation)
+ switch (IndentationMode)
{
case TwoSpaceIndentation:
jsonTextWriter.Formatting = Formatting.Indented;
diff --git a/src/dev/impl/DevToys/ViewModels/Tools/TextDiff/TextDiffToolViewModel.cs b/src/dev/impl/DevToys/ViewModels/Tools/TextDiff/TextDiffToolViewModel.cs
index 06e4302f41..097d2e1f5c 100644
--- a/src/dev/impl/DevToys/ViewModels/Tools/TextDiff/TextDiffToolViewModel.cs
+++ b/src/dev/impl/DevToys/ViewModels/Tools/TextDiff/TextDiffToolViewModel.cs
@@ -12,7 +12,15 @@ namespace DevToys.ViewModels.Tools.TextDiff
[Export(typeof(TextDiffToolViewModel))]
public sealed class TextDiffToolViewModel : ObservableRecipient, IToolViewModel
{
- private bool _inlineMode;
+ ///
+ /// Whether the text difference should be displayed inlined or side by side.
+ ///
+ private static readonly SettingDefinition Inline
+ = new(
+ name: $"{nameof(TextDiffToolViewModel)}.{nameof(Inline)}",
+ isRoaming: true,
+ defaultValue: false);
+
private string? _oldText;
private string? _newText;
@@ -24,8 +32,15 @@ public sealed class TextDiffToolViewModel : ObservableRecipient, IToolViewModel
internal bool InlineMode
{
- get => _inlineMode;
- set => SetProperty(ref _inlineMode, value, broadcast: true);
+ get => SettingsProvider.GetSetting(Inline);
+ set
+ {
+ if (SettingsProvider.GetSetting(Inline) != value)
+ {
+ SettingsProvider.SetSetting(Inline, value);
+ OnPropertyChanged();
+ }
+ }
}
internal string? OldText
diff --git a/src/dev/impl/DevToys/Views/Tools/JsonFormatter/JsonFormatterToolPage.xaml b/src/dev/impl/DevToys/Views/Tools/JsonFormatter/JsonFormatterToolPage.xaml
index b6a66e4454..ae0bc4a9ba 100644
--- a/src/dev/impl/DevToys/Views/Tools/JsonFormatter/JsonFormatterToolPage.xaml
+++ b/src/dev/impl/DevToys/Views/Tools/JsonFormatter/JsonFormatterToolPage.xaml
@@ -5,7 +5,6 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:DevToys.UI.Controls"
- xmlns:formattedtextblock="using:DevToys.UI.Controls.FormattedTextBlock"
xmlns:toolkit="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d"
NavigationCacheMode="Required">
@@ -34,7 +33,7 @@
+ SelectedValue="{x:Bind ViewModel.IndentationMode, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
diff --git a/src/dev/impl/DevToys/Views/Tools/JsonYaml/JsonYamlToolPage.xaml b/src/dev/impl/DevToys/Views/Tools/JsonYaml/JsonYamlToolPage.xaml
index f76937edb1..1d057b7476 100644
--- a/src/dev/impl/DevToys/Views/Tools/JsonYaml/JsonYamlToolPage.xaml
+++ b/src/dev/impl/DevToys/Views/Tools/JsonYaml/JsonYamlToolPage.xaml
@@ -5,8 +5,6 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="using:DevToys.UI.Controls"
- xmlns:formattedtextblock="using:DevToys.UI.Controls.FormattedTextBlock"
- xmlns:texteditor="using:DevToys.UI.Controls.TextEditor"
xmlns:ex="using:DevToys.UI.Extensions"
xmlns:toolkit="using:Microsoft.Toolkit.Uwp.UI.Controls"
mc:Ignorable="d"
@@ -61,7 +59,7 @@
+ SelectedValue="{x:Bind ViewModel.IndentationMode, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}">
diff --git a/src/tests/DevToys.Tests/Providers/Tools/HashGeneratorTests.cs b/src/tests/DevToys.Tests/Providers/Tools/HashGeneratorTests.cs
index a923bc25db..e088906c76 100644
--- a/src/tests/DevToys.Tests/Providers/Tools/HashGeneratorTests.cs
+++ b/src/tests/DevToys.Tests/Providers/Tools/HashGeneratorTests.cs
@@ -19,6 +19,7 @@ public async Task LowerCaseHashingAsync(string input, string expectedResult)
await ThreadHelper.RunOnUIThreadAsync(() =>
{
+ viewModel.IsUppercase = false;
viewModel.Input = input;
});