From 3e103af9132f26da9b2571882b50422cb0323726 Mon Sep 17 00:00:00 2001 From: MohammadHadi Attarieh Date: Wed, 6 Oct 2021 19:14:58 +0330 Subject: [PATCH] feat(DecimalFormatter): Implement FormatDouble and ParseDouble --- .../NumberBoxTests/Given_NumberBox.cs | 21 ++ .../NumberBoxTests/MUX_Test.xaml.cs | 6 +- src/Uno.UI.RuntimeTests/UnitTestsImport.props | 9 + .../Given_DecimalFormatter.cs | 290 ++++++++++++++++++ .../DecimalFormatter.cs | 165 +--------- .../INumberFormatter.cs | 13 +- .../INumberFormatter2.cs | 13 +- .../INumberFormatterOptions.cs | 77 +---- .../INumberParser.cs | 13 +- .../INumberRounderOption.cs | 13 +- .../ISignedZeroOption.cs | 13 +- .../ISignificantDigitsOption.cs | 13 +- .../NumberFormatting/DecimalFormatter.cs | 211 +++++++++++++ .../NumberFormatting/INumberFormatter.cs | 9 + .../NumberFormatting/INumberFormatter2.cs | 9 + .../INumberFormatterOptions.cs | 17 + .../NumberFormatting/INumberParser.cs | 9 + .../NumberFormatting/INumberRounderOption.cs | 7 + .../NumberFormatting/ISignedZeroOption.cs | 7 + .../ISignificantDigitsOption.cs | 7 + .../NumberFormatting/MathExtensions.cs | 17 + .../NumeralSystemTranslator.cs | 67 ++++ .../SignificantDigitsNumberRounder.cs | 12 +- 23 files changed, 703 insertions(+), 315 deletions(-) create mode 100644 src/Uno.UI.Tests/Windows_Globalization/Given_DecimalFormatter.cs create mode 100644 src/Uno.UWP/Globalization/NumberFormatting/DecimalFormatter.cs create mode 100644 src/Uno.UWP/Globalization/NumberFormatting/INumberFormatter.cs create mode 100644 src/Uno.UWP/Globalization/NumberFormatting/INumberFormatter2.cs create mode 100644 src/Uno.UWP/Globalization/NumberFormatting/INumberFormatterOptions.cs create mode 100644 src/Uno.UWP/Globalization/NumberFormatting/INumberParser.cs create mode 100644 src/Uno.UWP/Globalization/NumberFormatting/INumberRounderOption.cs create mode 100644 src/Uno.UWP/Globalization/NumberFormatting/ISignedZeroOption.cs create mode 100644 src/Uno.UWP/Globalization/NumberFormatting/ISignificantDigitsOption.cs create mode 100644 src/Uno.UWP/Globalization/NumberFormatting/MathExtensions.cs diff --git a/src/SamplesApp/SamplesApp.UITests/Microsoft_UI_Xaml_Controls/NumberBoxTests/Given_NumberBox.cs b/src/SamplesApp/SamplesApp.UITests/Microsoft_UI_Xaml_Controls/NumberBoxTests/Given_NumberBox.cs index 2b3fedf3b605..81bc178e1f8e 100644 --- a/src/SamplesApp/SamplesApp.UITests/Microsoft_UI_Xaml_Controls/NumberBoxTests/Given_NumberBox.cs +++ b/src/SamplesApp/SamplesApp.UITests/Microsoft_UI_Xaml_Controls/NumberBoxTests/Given_NumberBox.cs @@ -67,6 +67,27 @@ public void UpDownTest() Assert.AreEqual(55, numBox.GetDependencyPropertyValue("Value")); } + [Test] + [AutoRetry] + public void DecimalFormatterTest() + { + Run("UITests.Shared.Microsoft_UI_Xaml_Controls.NumberBoxTests.MUX_Test"); + + var numBox = _app.Marked("TestNumberBox"); + Assert.AreEqual(0, numBox.GetDependencyPropertyValue("Value")); + + _app.FastTap("MinCheckBox"); + _app.FastTap("MaxCheckBox"); + _app.Marked("CustomFormatterButton").FastTap(); + + numBox.ClearText(); + numBox.EnterText("۱٫۷"); + _app.PressEnter(); + + Assert.AreEqual("۱٫۷۵", numBox.GetDependencyPropertyValue("Text")); + Assert.AreEqual(1.75, numBox.GetDependencyPropertyValue("Value")); + } + [Test] [AutoRetry] public void MinMaxTest() diff --git a/src/SamplesApp/UITests.Shared/Microsoft_UI_Xaml_Controls/NumberBoxTests/MUX_Test.xaml.cs b/src/SamplesApp/UITests.Shared/Microsoft_UI_Xaml_Controls/NumberBoxTests/MUX_Test.xaml.cs index 4b1bdb253a52..3ac48bfc612f 100644 --- a/src/SamplesApp/UITests.Shared/Microsoft_UI_Xaml_Controls/NumberBoxTests/MUX_Test.xaml.cs +++ b/src/SamplesApp/UITests.Shared/Microsoft_UI_Xaml_Controls/NumberBoxTests/MUX_Test.xaml.cs @@ -101,10 +101,12 @@ private void NumberBoxValueChanged(object sender, Microsoft.UI.Xaml.Controls.Num private void CustomFormatterButton_Click(object sender, RoutedEventArgs e) { - List languages = new List() { "fr-FR" }; - DecimalFormatter formatter = new DecimalFormatter(languages, "FR"); + DecimalFormatter formatter = new DecimalFormatter(); formatter.IntegerDigits = 1; formatter.FractionDigits = 2; + formatter.NumeralSystem = "ArabExt"; + formatter.NumberRounder = new IncrementNumberRounder { Increment = 0.25 }; + TestNumberBox.NumberFormatter = formatter; } diff --git a/src/Uno.UI.RuntimeTests/UnitTestsImport.props b/src/Uno.UI.RuntimeTests/UnitTestsImport.props index 482b07b1e334..d4f2fbef2243 100644 --- a/src/Uno.UI.RuntimeTests/UnitTestsImport.props +++ b/src/Uno.UI.RuntimeTests/UnitTestsImport.props @@ -29,6 +29,15 @@ UnitTests\Windows_Globalization\%(RecursiveDir)%(FileName)%(Extension) + + UnitTests\Windows_Globalization\%(RecursiveDir)%(FileName)%(Extension) + + + UnitTests\Windows_Globalization\%(RecursiveDir)%(FileName)%(Extension) + + + UnitTests\Windows_Globalization\%(RecursiveDir)%(FileName)%(Extension) + diff --git a/src/Uno.UI.Tests/Windows_Globalization/Given_DecimalFormatter.cs b/src/Uno.UI.Tests/Windows_Globalization/Given_DecimalFormatter.cs new file mode 100644 index 000000000000..aec913dc8649 --- /dev/null +++ b/src/Uno.UI.Tests/Windows_Globalization/Given_DecimalFormatter.cs @@ -0,0 +1,290 @@ + +using System; +using Microsoft.VisualStudio.TestTools.UnitTesting; +using Windows.Globalization.NumberFormatting; + +namespace Uno.UI.Tests.Windows_Globalization +{ + [TestClass] + public class Given_DecimalFormatter + { + [DataTestMethod] + [DataRow(double.PositiveInfinity, "∞")] + [DataRow(double.NegativeInfinity, "-∞")] + [DataRow(double.NaN, "NaN")] + public void When_FormatSpecialDouble(double value, string expected) + { + DecimalFormatter df = new DecimalFormatter(); + var actual = df.FormatDouble(value); + + Assert.AreEqual(expected, actual); + } + + [DataTestMethod] + [DataRow(1.5d, 1, 2, "1.50")] + [DataRow(1.567d, 1, 2, "1.567")] + [DataRow(1.5602d, 1, 2, "1.5602")] + [DataRow(0d, 0, 0, "0")] + [DataRow(-0d, 0, 0, "0")] + [DataRow(0d, 0, 2, ".00")] + [DataRow(-0d, 0, 2, ".00")] + [DataRow(0d, 2, 0, "00")] + [DataRow(-0d, 2, 0, "00")] + [DataRow(0d, 3, 1, "000.0")] + [DataRow(-0d, 3, 1, "000.0")] + public void When_FormatDouble(double value, int integerDigits, int fractionDigits, string expected) + { + DecimalFormatter df = new DecimalFormatter(); + df.IntegerDigits = integerDigits; + df.FractionDigits = fractionDigits; + + var formatted = df.FormatDouble(value); + Assert.AreEqual(expected, formatted); + } + + [DataTestMethod] + [DataRow(1234, 2, 0, "1,234")] + [DataRow(1234, 6, 0, "001,234")] + [DataRow(1234.56, 2, 2, "1,234.56")] + [DataRow(1234.0, 6, 2, "001,234.00")] + [DataRow(1234.0, 6, 0, "001,234")] + public void When_FormatDoubleWithIsGroupSetTrue(double value, int integerDigits, int fractionDigits, string expected) + { + DecimalFormatter df = new DecimalFormatter(); + df.IntegerDigits = integerDigits; + df.FractionDigits = fractionDigits; + df.IsGrouped = true; + + var formatted = df.FormatDouble(value); + Assert.AreEqual(expected, formatted); + } + + [DataTestMethod] + [DataRow(0, 0, "-0")] + [DataRow(0, 2, "-.00")] + [DataRow(2, 0, "-00")] + [DataRow(3, 1, "-000.0")] + public void When_FormatDoubleMinusZeroWithIsZeroSignedSetTrue(int integerDigits, int fractionDigits, string expected) + { + DecimalFormatter df = new DecimalFormatter(); + df.IntegerDigits = integerDigits; + df.FractionDigits = fractionDigits; + df.IsZeroSigned = true; + + var formatted = df.FormatDouble(-0d); + Assert.AreEqual(expected, formatted); + } + + [DataTestMethod] + [DataRow(0, 0, "0")] + [DataRow(0, 2, ".00")] + [DataRow(2, 0, "00")] + [DataRow(3, 1, "000.0")] + public void When_FormatDoubleZeroWithIsZeroSignedSetTrue(int integerDigits, int fractionDigits, string expected) + { + DecimalFormatter df = new DecimalFormatter(); + df.IntegerDigits = integerDigits; + df.FractionDigits = fractionDigits; + df.IsZeroSigned = true; + + var formatted = df.FormatDouble(0d); + Assert.AreEqual(expected, formatted); + } + + [DataTestMethod] + [DataRow(1d, "1.")] + public void When_FormatDoubleWithIsDecimalPointerAlwaysDisplayedSetTrue(double value, string expected) + { + DecimalFormatter df = new DecimalFormatter(); + df.IsDecimalPointAlwaysDisplayed = true; + df.FractionDigits = 0; + df.IntegerDigits = 0; + + var formatted = df.FormatDouble(value); + Assert.AreEqual(expected, formatted); + } + + [DataTestMethod] + [DataRow(123.4567d, 5, 1, 2, "123.4567")] + [DataRow(123.4567d, 10, 1, 2, "123.4567000")] + [DataRow(123.4567d, 2, 1, 2, "123.4567")] + [DataRow(12.3d, 4, 1, 2, "12.30")] + [DataRow(12.3d, 4, 1, 0, "12.30")] + public void When_FormatDoubleWithSpecificSignificantDigits(double value, int significantDigits, int integerDigits, int fractionDigits, string expected) + { + DecimalFormatter df = new DecimalFormatter(); + df.SignificantDigits = significantDigits; + df.IntegerDigits = integerDigits; + df.FractionDigits = fractionDigits; + + var formatted = df.FormatDouble(value); + Assert.AreEqual(expected, formatted); + } + + [TestMethod] + public void When_FormatDoubleUsingIncrementNumberRounder() + { + DecimalFormatter df = new DecimalFormatter(); + IncrementNumberRounder rounder = new IncrementNumberRounder(); + rounder.Increment = 0.5; + df.NumberRounder = rounder; + var formatted = df.FormatDouble(1.8); + + Assert.AreEqual("2.00", formatted); + } + + [TestMethod] + public void When_FormatDoubleUsingSignificantDigitsNumberRounder() + { + DecimalFormatter df = new DecimalFormatter(); + SignificantDigitsNumberRounder rounder = new SignificantDigitsNumberRounder(); + rounder.SignificantDigits = 1; + df.NumberRounder = rounder; + var formatted = df.FormatDouble(1.8); + + Assert.AreEqual("2.00", formatted); + } + + [TestMethod] + public void When_Initialize() + { + DecimalFormatter df = new DecimalFormatter(); + + Assert.AreEqual(0, df.SignificantDigits); + Assert.AreEqual(1, df.IntegerDigits); + Assert.AreEqual(2, df.FractionDigits); + Assert.AreEqual(false, df.IsGrouped); + Assert.AreEqual(false, df.IsZeroSigned); + Assert.AreEqual(false, df.IsDecimalPointAlwaysDisplayed); + Assert.AreEqual("en-US", df.ResolvedLanguage); + Assert.IsNull(df.NumberRounder); + /* + FractionDigits 2 int + GeographicRegion "US" string + IntegerDigits 1 int + IsDecimalPointAlwaysDisplayed false bool + IsGrouped false bool + IsZeroSigned false bool + NumberRounder null WindoGlobalization.NumberFormatting.INumberRounder + NumeralSystem "Latn" string + ResolvedGeographicRegion "ZZ" string + ResolvedLanguage "en-US" string + SignificantDigits 0 int + + */ + } + + [DataTestMethod] + [DataRow("1.2", 1.2)] + [DataRow("1.20", 1.2)] + [DataRow("12,34.2", null)] + [DataRow("0", 0d)] + public void When_ParseDouble(string value, double? expected) + { + DecimalFormatter df = new DecimalFormatter(); + df.FractionDigits = 2; + + var actual = df.ParseDouble(value); + Assert.AreEqual(expected, actual); + } + + [DataTestMethod] + [DataRow("1234.2", 1234.2)] + [DataRow("1,234.2", 1234.2)] + [DataRow("12,34.2", null)] + public void When_ParseDoubleAndIsGroupSetTrue(string value, double? expected) + { + DecimalFormatter df = new DecimalFormatter(); + df.FractionDigits = 2; + df.IsGrouped = true; + + var actual = df.ParseDouble(value); + Assert.AreEqual(expected, actual); + } + + [DataTestMethod] + [DataRow("1", 1d)] + [DataRow("1.", 1d)] + public void When_ParseDoubleAndIsDecimalPointAlwaysDisplayedSetTrue(string value, double? expected) + { + DecimalFormatter df = new DecimalFormatter(); + df.FractionDigits = 2; + df.IsDecimalPointAlwaysDisplayed = true; + + var actual = df.ParseDouble(value); + Assert.AreEqual(expected, actual); + } + + [TestMethod] + public void When_ParseDoubleMinusZero() + { + DecimalFormatter df = new DecimalFormatter(); + var actual = df.ParseDouble("-0"); + bool isNegative = false; + + if (actual.HasValue) + { + isNegative = BitConverter.DoubleToInt64Bits(actual.Value) < 0; + } + + Assert.AreEqual(true, isNegative); + } + + [DataTestMethod] + [DataRow("Arab")] + [DataRow("ArabExt")] + [DataRow("Bali")] + [DataRow("Beng")] + [DataRow("Cham")] + [DataRow("Deva")] + [DataRow("FullWide")] + [DataRow("Gujr")] + [DataRow("Guru")] + [DataRow("Java")] + [DataRow("Kali")] + [DataRow("Khmr")] + [DataRow("Knda")] + [DataRow("Lana")] + [DataRow("LanaTham")] + [DataRow("Laoo")] + [DataRow("Latn")] + [DataRow("Lepc")] + [DataRow("Limb")] + [DataRow("Mlym")] + [DataRow("Mong")] + [DataRow("Mtei")] + [DataRow("Mymr")] + [DataRow("MymrShan")] + [DataRow("Nkoo")] + [DataRow("Olck")] + [DataRow("Orya")] + [DataRow("Saur")] + [DataRow("Sund")] + [DataRow("Talu")] + [DataRow("TamlDec")] + [DataRow("Telu")] + [DataRow("Thai")] + [DataRow("Tibt")] + [DataRow("Vaii")] + public void When_ParseDoubleUsingSpeceficNumeralSystem(string numeralSystem) + { + DecimalFormatter df = new DecimalFormatter(); + df.NumeralSystem = numeralSystem; + + var translator = new NumeralSystemTranslator { NumeralSystem = numeralSystem }; + var translated = translator.TranslateNumerals("1234.56789"); + + var actual = df.ParseDouble(translated); + Assert.AreEqual(1234.56789, actual); + } + + [TestMethod] + public void When_ParseNotValidDouble() + { + DecimalFormatter df = new DecimalFormatter(); + + var actual = df.ParseDouble("a12"); + Assert.AreEqual(null, actual); + } + } +} diff --git a/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/DecimalFormatter.cs b/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/DecimalFormatter.cs index 7f201debfac9..735121b4bbe2 100644 --- a/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/DecimalFormatter.cs +++ b/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/DecimalFormatter.cs @@ -2,81 +2,11 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.Globalization.NumberFormatting { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false || false || false || false || false || false || false [global::Uno.NotImplemented] #endif public partial class DecimalFormatter : global::Windows.Globalization.NumberFormatting.INumberFormatterOptions,global::Windows.Globalization.NumberFormatting.INumberFormatter,global::Windows.Globalization.NumberFormatting.INumberFormatter2,global::Windows.Globalization.NumberFormatting.INumberParser,global::Windows.Globalization.NumberFormatting.ISignificantDigitsOption,global::Windows.Globalization.NumberFormatting.INumberRounderOption,global::Windows.Globalization.NumberFormatting.ISignedZeroOption { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public bool IsDecimalPointAlwaysDisplayed - { - get - { - throw new global::System.NotImplementedException("The member bool DecimalFormatter.IsDecimalPointAlwaysDisplayed is not implemented in Uno."); - } - set - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.Globalization.NumberFormatting.DecimalFormatter", "bool DecimalFormatter.IsDecimalPointAlwaysDisplayed"); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public int IntegerDigits - { - get - { - throw new global::System.NotImplementedException("The member int DecimalFormatter.IntegerDigits is not implemented in Uno."); - } - set - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.Globalization.NumberFormatting.DecimalFormatter", "int DecimalFormatter.IntegerDigits"); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public bool IsGrouped - { - get - { - throw new global::System.NotImplementedException("The member bool DecimalFormatter.IsGrouped is not implemented in Uno."); - } - set - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.Globalization.NumberFormatting.DecimalFormatter", "bool DecimalFormatter.IsGrouped"); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public string NumeralSystem - { - get - { - throw new global::System.NotImplementedException("The member string DecimalFormatter.NumeralSystem is not implemented in Uno."); - } - set - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.Globalization.NumberFormatting.DecimalFormatter", "string DecimalFormatter.NumeralSystem"); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public int FractionDigits - { - get - { - throw new global::System.NotImplementedException("The member int DecimalFormatter.FractionDigits is not implemented in Uno."); - } - set - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.Globalization.NumberFormatting.DecimalFormatter", "int DecimalFormatter.FractionDigits"); - } - } - #endif #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] public string GeographicRegion @@ -87,16 +17,7 @@ public string GeographicRegion } } #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public global::System.Collections.Generic.IReadOnlyList Languages - { - get - { - throw new global::System.NotImplementedException("The member IReadOnlyList DecimalFormatter.Languages is not implemented in Uno."); - } - } - #endif + #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] public string ResolvedGeographicRegion @@ -107,58 +28,8 @@ public string ResolvedGeographicRegion } } #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public string ResolvedLanguage - { - get - { - throw new global::System.NotImplementedException("The member string DecimalFormatter.ResolvedLanguage is not implemented in Uno."); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public global::Windows.Globalization.NumberFormatting.INumberRounder NumberRounder - { - get - { - throw new global::System.NotImplementedException("The member INumberRounder DecimalFormatter.NumberRounder is not implemented in Uno."); - } - set - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.Globalization.NumberFormatting.DecimalFormatter", "INumberRounder DecimalFormatter.NumberRounder"); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public bool IsZeroSigned - { - get - { - throw new global::System.NotImplementedException("The member bool DecimalFormatter.IsZeroSigned is not implemented in Uno."); - } - set - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.Globalization.NumberFormatting.DecimalFormatter", "bool DecimalFormatter.IsZeroSigned"); - } - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public int SignificantDigits - { - get - { - throw new global::System.NotImplementedException("The member int DecimalFormatter.SignificantDigits is not implemented in Uno."); - } - set - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.Globalization.NumberFormatting.DecimalFormatter", "int DecimalFormatter.SignificantDigits"); - } - } - #endif + + #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] public DecimalFormatter( global::System.Collections.Generic.IEnumerable languages, string geographicRegion) @@ -167,13 +38,6 @@ public DecimalFormatter( global::System.Collections.Generic.IEnumerable } #endif // Forced skipping of method Windows.Globalization.NumberFormatting.DecimalFormatter.DecimalFormatter(System.Collections.Generic.IEnumerable, string) - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public DecimalFormatter() - { - global::Windows.Foundation.Metadata.ApiInformation.TryRaiseNotImplemented("Windows.Globalization.NumberFormatting.DecimalFormatter", "DecimalFormatter.DecimalFormatter()"); - } - #endif // Forced skipping of method Windows.Globalization.NumberFormatting.DecimalFormatter.DecimalFormatter() // Forced skipping of method Windows.Globalization.NumberFormatting.DecimalFormatter.Languages.get // Forced skipping of method Windows.Globalization.NumberFormatting.DecimalFormatter.GeographicRegion.get @@ -205,13 +69,6 @@ public string Format( ulong value) #endif #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public string Format( double value) - { - throw new global::System.NotImplementedException("The member string DecimalFormatter.Format(double value) is not implemented in Uno."); - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] public string FormatInt( long value) { throw new global::System.NotImplementedException("The member string DecimalFormatter.FormatInt(long value) is not implemented in Uno."); @@ -226,13 +83,6 @@ public string FormatUInt( ulong value) #endif #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public string FormatDouble( double value) - { - throw new global::System.NotImplementedException("The member string DecimalFormatter.FormatDouble(double value) is not implemented in Uno."); - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] public long? ParseInt( string text) { throw new global::System.NotImplementedException("The member long? DecimalFormatter.ParseInt(string text) is not implemented in Uno."); @@ -245,13 +95,6 @@ public string FormatDouble( double value) throw new global::System.NotImplementedException("The member ulong? DecimalFormatter.ParseUInt(string text) is not implemented in Uno."); } #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - [global::Uno.NotImplemented("__ANDROID__", "__IOS__", "NET461", "__WASM__", "__SKIA__", "__NETSTD_REFERENCE__", "__MACOS__")] - public double? ParseDouble( string text) - { - throw new global::System.NotImplementedException("The member double? DecimalFormatter.ParseDouble(string text) is not implemented in Uno."); - } - #endif // Forced skipping of method Windows.Globalization.NumberFormatting.DecimalFormatter.SignificantDigits.get // Forced skipping of method Windows.Globalization.NumberFormatting.DecimalFormatter.SignificantDigits.set // Forced skipping of method Windows.Globalization.NumberFormatting.DecimalFormatter.NumberRounder.get diff --git a/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/INumberFormatter.cs b/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/INumberFormatter.cs index af01b014bdfb..e34f3d286d36 100644 --- a/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/INumberFormatter.cs +++ b/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/INumberFormatter.cs @@ -2,19 +2,10 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.Globalization.NumberFormatting { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false || false || false || false || false || false || false [global::Uno.NotImplemented] #endif - public partial interface INumberFormatter + public partial interface INumberFormatter { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - string Format( long value); - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - string Format( ulong value); - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - string Format( double value); - #endif } } diff --git a/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/INumberFormatter2.cs b/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/INumberFormatter2.cs index d82f1a4d3df0..b51a7919dd1e 100644 --- a/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/INumberFormatter2.cs +++ b/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/INumberFormatter2.cs @@ -2,19 +2,10 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.Globalization.NumberFormatting { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false || false || false || false || false || false || false [global::Uno.NotImplemented] #endif - public partial interface INumberFormatter2 + public partial interface INumberFormatter2 { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - string FormatInt( long value); - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - string FormatUInt( ulong value); - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - string FormatDouble( double value); - #endif } } diff --git a/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/INumberFormatterOptions.cs b/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/INumberFormatterOptions.cs index 9c20d4712c44..c26a7c9f2e0a 100644 --- a/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/INumberFormatterOptions.cs +++ b/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/INumberFormatterOptions.cs @@ -2,83 +2,10 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.Globalization.NumberFormatting { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false || false || false || false || false || false || false [global::Uno.NotImplemented] #endif - public partial interface INumberFormatterOptions + public partial interface INumberFormatterOptions { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - int FractionDigits - { - get; - set; - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - string GeographicRegion - { - get; - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - int IntegerDigits - { - get; - set; - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - bool IsDecimalPointAlwaysDisplayed - { - get; - set; - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - bool IsGrouped - { - get; - set; - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - global::System.Collections.Generic.IReadOnlyList Languages - { - get; - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - string NumeralSystem - { - get; - set; - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - string ResolvedGeographicRegion - { - get; - } - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - string ResolvedLanguage - { - get; - } - #endif - // Forced skipping of method Windows.Globalization.NumberFormatting.INumberFormatterOptions.Languages.get - // Forced skipping of method Windows.Globalization.NumberFormatting.INumberFormatterOptions.GeographicRegion.get - // Forced skipping of method Windows.Globalization.NumberFormatting.INumberFormatterOptions.IntegerDigits.get - // Forced skipping of method Windows.Globalization.NumberFormatting.INumberFormatterOptions.IntegerDigits.set - // Forced skipping of method Windows.Globalization.NumberFormatting.INumberFormatterOptions.FractionDigits.get - // Forced skipping of method Windows.Globalization.NumberFormatting.INumberFormatterOptions.FractionDigits.set - // Forced skipping of method Windows.Globalization.NumberFormatting.INumberFormatterOptions.IsGrouped.get - // Forced skipping of method Windows.Globalization.NumberFormatting.INumberFormatterOptions.IsGrouped.set - // Forced skipping of method Windows.Globalization.NumberFormatting.INumberFormatterOptions.IsDecimalPointAlwaysDisplayed.get - // Forced skipping of method Windows.Globalization.NumberFormatting.INumberFormatterOptions.IsDecimalPointAlwaysDisplayed.set - // Forced skipping of method Windows.Globalization.NumberFormatting.INumberFormatterOptions.NumeralSystem.get - // Forced skipping of method Windows.Globalization.NumberFormatting.INumberFormatterOptions.NumeralSystem.set - // Forced skipping of method Windows.Globalization.NumberFormatting.INumberFormatterOptions.ResolvedLanguage.get - // Forced skipping of method Windows.Globalization.NumberFormatting.INumberFormatterOptions.ResolvedGeographicRegion.get } } diff --git a/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/INumberParser.cs b/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/INumberParser.cs index 98e2edb9daf4..5cde10416b66 100644 --- a/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/INumberParser.cs +++ b/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/INumberParser.cs @@ -2,19 +2,10 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.Globalization.NumberFormatting { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false || false || false || false || false || false || false [global::Uno.NotImplemented] #endif - public partial interface INumberParser + public partial interface INumberParser { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - long? ParseInt( string text); - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - ulong? ParseUInt( string text); - #endif - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - double? ParseDouble( string text); - #endif } } diff --git a/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/INumberRounderOption.cs b/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/INumberRounderOption.cs index a80447d3b587..62ced5764bfc 100644 --- a/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/INumberRounderOption.cs +++ b/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/INumberRounderOption.cs @@ -2,19 +2,10 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.Globalization.NumberFormatting { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false || false || false || false || false || false || false [global::Uno.NotImplemented] #endif - public partial interface INumberRounderOption + public partial interface INumberRounderOption { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - global::Windows.Globalization.NumberFormatting.INumberRounder NumberRounder - { - get; - set; - } - #endif - // Forced skipping of method Windows.Globalization.NumberFormatting.INumberRounderOption.NumberRounder.get - // Forced skipping of method Windows.Globalization.NumberFormatting.INumberRounderOption.NumberRounder.set } } diff --git a/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/ISignedZeroOption.cs b/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/ISignedZeroOption.cs index 9b7a9724d9cd..52c26ffcbd91 100644 --- a/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/ISignedZeroOption.cs +++ b/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/ISignedZeroOption.cs @@ -2,19 +2,10 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.Globalization.NumberFormatting { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false || false || false || false || false || false || false [global::Uno.NotImplemented] #endif - public partial interface ISignedZeroOption + public partial interface ISignedZeroOption { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - bool IsZeroSigned - { - get; - set; - } - #endif - // Forced skipping of method Windows.Globalization.NumberFormatting.ISignedZeroOption.IsZeroSigned.get - // Forced skipping of method Windows.Globalization.NumberFormatting.ISignedZeroOption.IsZeroSigned.set } } diff --git a/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/ISignificantDigitsOption.cs b/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/ISignificantDigitsOption.cs index b8caebdf962d..c525b6061320 100644 --- a/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/ISignificantDigitsOption.cs +++ b/src/Uno.UWP/Generated/3.0.0.0/Windows.Globalization.NumberFormatting/ISignificantDigitsOption.cs @@ -2,19 +2,10 @@ #pragma warning disable 114 // new keyword hiding namespace Windows.Globalization.NumberFormatting { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ + #if false || false || false || false || false || false || false [global::Uno.NotImplemented] #endif - public partial interface ISignificantDigitsOption + public partial interface ISignificantDigitsOption { - #if __ANDROID__ || __IOS__ || NET461 || __WASM__ || __SKIA__ || __NETSTD_REFERENCE__ || __MACOS__ - int SignificantDigits - { - get; - set; - } - #endif - // Forced skipping of method Windows.Globalization.NumberFormatting.ISignificantDigitsOption.SignificantDigits.get - // Forced skipping of method Windows.Globalization.NumberFormatting.ISignificantDigitsOption.SignificantDigits.set } } diff --git a/src/Uno.UWP/Globalization/NumberFormatting/DecimalFormatter.cs b/src/Uno.UWP/Globalization/NumberFormatting/DecimalFormatter.cs new file mode 100644 index 000000000000..ace8dc46dc09 --- /dev/null +++ b/src/Uno.UWP/Globalization/NumberFormatting/DecimalFormatter.cs @@ -0,0 +1,211 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Linq; + +namespace Windows.Globalization.NumberFormatting +{ + public partial class DecimalFormatter : INumberFormatterOptions, INumberFormatter, INumberFormatter2, INumberParser, ISignificantDigitsOption, INumberRounderOption, ISignedZeroOption + { + private readonly NumeralSystemTranslator _translator; + + public DecimalFormatter() + { + _translator = new NumeralSystemTranslator(); + } + + public bool IsDecimalPointAlwaysDisplayed { get; set; } + + public int IntegerDigits { get; set; } = 1; + + public bool IsGrouped { get; set; } + + public string NumeralSystem + { + get => _translator.NumeralSystem; + set => _translator.NumeralSystem = value; + } + + public IReadOnlyList Languages => _translator.Languages; + + public string ResolvedLanguage => _translator.ResolvedLanguage; + + public int FractionDigits { get; set; } = 2; + + public INumberRounder NumberRounder { get; set; } + + public bool IsZeroSigned { get; set; } + + public int SignificantDigits { get; set; } = 0; + + public string Format(double value) => FormatDouble(value); + + public string FormatDouble(double value) + { + if (double.IsNaN(value)) + { + return "NaN"; + } + + if (double.IsPositiveInfinity(value)) + { + return "∞"; + } + + if (double.IsNegativeInfinity(value)) + { + return "-∞"; + } + + if (NumberRounder != null) + { + value = NumberRounder.RoundDouble(value); + } + + bool isNegative = BitConverter.DoubleToInt64Bits(value) < 0; + + if (value == 0d && + IntegerDigits == 0 && + FractionDigits == 0) + { + if (isNegative && IsZeroSigned) + { + var r = CultureInfo.InvariantCulture.NumberFormat.NegativeSign + "0"; + return _translator.TranslateNumerals(r); + } + else + { + return _translator.TranslateNumerals("0"); + } + } + + bool addMinusSign = isNegative && value == 0; + + var formattedFractionPart = FormatFractionPart(value); + var formattedIntegerPart = FormatIntegerPart(value); + var formatted = formattedIntegerPart + formattedFractionPart; + + if (IsDecimalPointAlwaysDisplayed && + formattedFractionPart == string.Empty) + { + formatted += CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator; + } + + if (addMinusSign && IsZeroSigned) + { + formatted = CultureInfo.InvariantCulture.NumberFormat.NegativeSign + formatted; + } + + formatted = _translator.TranslateNumerals(formatted); + return formatted; + } + + private string FormatIntegerPart(double value) + { + var integerPart = (int)Math.Truncate(value); + + if (integerPart == 0 && + IntegerDigits == 0) + { + return string.Empty; + } + else if (IsGrouped) + { + var zeros = new string(Enumerable.Repeat('0', IntegerDigits - 1).ToArray()); + var format = string.Concat(zeros, ",0"); + return integerPart.ToString(format, CultureInfo.InvariantCulture); + } + else + { + return integerPart.ToString($"D{IntegerDigits}", CultureInfo.InvariantCulture); + } + } + + private string FormatFractionPart(double value) + { + var numberDecimalSeparator = CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator; + + var integerPart = (int)Math.Truncate(value); + var integerPartLen = integerPart.GetLength(); + var fractionDigits = Math.Max(FractionDigits, SignificantDigits - integerPartLen); + var rounded = Math.Round(value, fractionDigits, MidpointRounding.AwayFromZero); + var needZeros = value == rounded; + var formattedFractionPart = needZeros ? value.ToString($"F{fractionDigits}", CultureInfo.InvariantCulture) : value.ToString(CultureInfo.InvariantCulture); + var indexOfDecimalSeperator = formattedFractionPart.LastIndexOf(numberDecimalSeparator, StringComparison.Ordinal); + + if (indexOfDecimalSeperator == -1) + { + formattedFractionPart = string.Empty; + } + else + { + formattedFractionPart = formattedFractionPart.Substring(indexOfDecimalSeperator); + } + + return formattedFractionPart; + } + + public double? ParseDouble(string text) + { + text = _translator.TranslateBackNumerals(text); + + if (HasInvalidGroupSize(text)) + { + return null; + } + + if (!double.TryParse(text, + NumberStyles.Float | NumberStyles.AllowThousands, + CultureInfo.InvariantCulture, out double value)) + { + return null; + } + + if (value == 0 && + text.IndexOf(CultureInfo.InvariantCulture.NumberFormat.NegativeSign, StringComparison.Ordinal) != -1) + { + return -0d; + } + + return value; + } + + private bool HasInvalidGroupSize(string text) + { + var numberFormat = CultureInfo.InvariantCulture.NumberFormat; + var decimalSeperatorIndex = text.LastIndexOf(numberFormat.NumberDecimalSeparator, StringComparison.Ordinal); + var groupSize = numberFormat.NumberGroupSizes[0]; + var groupSeperatorLength = numberFormat.NumberGroupSeparator.Length; + var groupSeperator = numberFormat.NumberGroupSeparator; + + var preIndex = text.IndexOf(groupSeperator, StringComparison.Ordinal); + var Index = -1; + + if (preIndex != -1) + { + while (preIndex + groupSeperatorLength < text.Length) + { + Index = text.IndexOf(groupSeperator, preIndex + groupSeperatorLength, StringComparison.Ordinal); + + if (Index == -1) + { + if (decimalSeperatorIndex - preIndex - groupSeperatorLength != groupSize) + { + return true; + } + + break; + } + else if (Index - preIndex != groupSize) + { + return true; + } + + preIndex = Index; + } + } + + return false; + } + } +} diff --git a/src/Uno.UWP/Globalization/NumberFormatting/INumberFormatter.cs b/src/Uno.UWP/Globalization/NumberFormatting/INumberFormatter.cs new file mode 100644 index 000000000000..9a1ac0448e5d --- /dev/null +++ b/src/Uno.UWP/Globalization/NumberFormatting/INumberFormatter.cs @@ -0,0 +1,9 @@ +namespace Windows.Globalization.NumberFormatting +{ + public partial interface INumberFormatter + { + string Format(long value); + string Format(ulong value); + string Format(double value); + } +} diff --git a/src/Uno.UWP/Globalization/NumberFormatting/INumberFormatter2.cs b/src/Uno.UWP/Globalization/NumberFormatting/INumberFormatter2.cs new file mode 100644 index 000000000000..4b3af41825ad --- /dev/null +++ b/src/Uno.UWP/Globalization/NumberFormatting/INumberFormatter2.cs @@ -0,0 +1,9 @@ +namespace Windows.Globalization.NumberFormatting +{ + public partial interface INumberFormatter2 + { + string FormatInt(long value); + string FormatUInt(ulong value); + string FormatDouble(double value); + } +} diff --git a/src/Uno.UWP/Globalization/NumberFormatting/INumberFormatterOptions.cs b/src/Uno.UWP/Globalization/NumberFormatting/INumberFormatterOptions.cs new file mode 100644 index 000000000000..c6760e602f2a --- /dev/null +++ b/src/Uno.UWP/Globalization/NumberFormatting/INumberFormatterOptions.cs @@ -0,0 +1,17 @@ +using System.Collections.Generic; + +namespace Windows.Globalization.NumberFormatting +{ + public partial interface INumberFormatterOptions + { + int FractionDigits { get; set; } + string GeographicRegion { get; } + int IntegerDigits { get; set; } + bool IsDecimalPointAlwaysDisplayed { get; set; } + bool IsGrouped { get; set; } + IReadOnlyList Languages { get; } + string NumeralSystem { get; set; } + string ResolvedGeographicRegion { get; } + string ResolvedLanguage { get; } + } +} diff --git a/src/Uno.UWP/Globalization/NumberFormatting/INumberParser.cs b/src/Uno.UWP/Globalization/NumberFormatting/INumberParser.cs new file mode 100644 index 000000000000..672736d50a1a --- /dev/null +++ b/src/Uno.UWP/Globalization/NumberFormatting/INumberParser.cs @@ -0,0 +1,9 @@ +namespace Windows.Globalization.NumberFormatting +{ + public partial interface INumberParser + { + long? ParseInt(string text); + ulong? ParseUInt(string text); + double? ParseDouble(string text); + } +} diff --git a/src/Uno.UWP/Globalization/NumberFormatting/INumberRounderOption.cs b/src/Uno.UWP/Globalization/NumberFormatting/INumberRounderOption.cs new file mode 100644 index 000000000000..b38047a0036f --- /dev/null +++ b/src/Uno.UWP/Globalization/NumberFormatting/INumberRounderOption.cs @@ -0,0 +1,7 @@ +namespace Windows.Globalization.NumberFormatting +{ + public partial interface INumberRounderOption + { + INumberRounder NumberRounder { get; set; } + } +} diff --git a/src/Uno.UWP/Globalization/NumberFormatting/ISignedZeroOption.cs b/src/Uno.UWP/Globalization/NumberFormatting/ISignedZeroOption.cs new file mode 100644 index 000000000000..7f48f4d4cd81 --- /dev/null +++ b/src/Uno.UWP/Globalization/NumberFormatting/ISignedZeroOption.cs @@ -0,0 +1,7 @@ +namespace Windows.Globalization.NumberFormatting +{ + public partial interface ISignedZeroOption + { + bool IsZeroSigned { get; set; } + } +} diff --git a/src/Uno.UWP/Globalization/NumberFormatting/ISignificantDigitsOption.cs b/src/Uno.UWP/Globalization/NumberFormatting/ISignificantDigitsOption.cs new file mode 100644 index 000000000000..963d02430e23 --- /dev/null +++ b/src/Uno.UWP/Globalization/NumberFormatting/ISignificantDigitsOption.cs @@ -0,0 +1,7 @@ +namespace Windows.Globalization.NumberFormatting +{ + public partial interface ISignificantDigitsOption + { + int SignificantDigits { get; set; } + } +} diff --git a/src/Uno.UWP/Globalization/NumberFormatting/MathExtensions.cs b/src/Uno.UWP/Globalization/NumberFormatting/MathExtensions.cs new file mode 100644 index 000000000000..297a17bb9345 --- /dev/null +++ b/src/Uno.UWP/Globalization/NumberFormatting/MathExtensions.cs @@ -0,0 +1,17 @@ +using System; + +namespace Windows.Globalization.NumberFormatting +{ + internal static class MathExtensions + { + public static int GetLength(this int input) + { + if (input == 0) + { + return 1; + } + + return (int)Math.Floor(Math.Log10(Math.Abs(input))) + 1; + } + } +} diff --git a/src/Uno.UWP/Globalization/NumberFormatting/NumeralSystemTranslator.cs b/src/Uno.UWP/Globalization/NumberFormatting/NumeralSystemTranslator.cs index 75e13b5c64f0..867eda8963cc 100644 --- a/src/Uno.UWP/Globalization/NumberFormatting/NumeralSystemTranslator.cs +++ b/src/Uno.UWP/Globalization/NumberFormatting/NumeralSystemTranslator.cs @@ -166,5 +166,72 @@ private static char Translate(char c, char[] digitsSource) return t; } + + public string TranslateBackNumerals(string value) + { + if (NumeralSystem.Equals("Arab", StringComparison.Ordinal) || + NumeralSystem.Equals("ArabExt", StringComparison.Ordinal)) + { + return TranslateBackArab(value, NumeralSystemTranslatorHelper.GetDigitsSource(NumeralSystem)); + } + + return TranslateBack(value, NumeralSystemTranslatorHelper.GetDigitsSource(NumeralSystem)); + } + + private static string TranslateBackArab(string value, char[] digitsSource) + { + var chars = value.ToCharArray(); + + for (int i = 0; i < chars.Length; i++) + { + var c = chars[i]; + + switch (c) + { + case '\u066b': + chars[i] = '.'; + break; + case '\u066c': + chars[i] = ','; + break; + case '\u066a': + chars[i] = '%'; + break; + case '\u0609': //Per Mille Symbol + chars[i] = '\u2030'; + break; + default: + chars[i] = TranslateBack(c, digitsSource); + break; + } + } + + return new string(chars); + } + + private static string TranslateBack(string value, char[] digitsSource) + { + var chars = value.ToCharArray(); + + for (int i = 0; i < chars.Length; i++) + { + chars[i] = TranslateBack(chars[i], digitsSource); + } + + return new string(chars); + } + + private static char TranslateBack(char c, char[] digitsSource) + { + var d = c - digitsSource[0]; + var t = c; + + if (d >= 0 && d <= 9) + { + t = (char)(d + '0'); + } + + return t; + } } } diff --git a/src/Uno.UWP/Globalization/NumberFormatting/SignificantDigitsNumberRounder.cs b/src/Uno.UWP/Globalization/NumberFormatting/SignificantDigitsNumberRounder.cs index 3969073b8cd2..3e85fb9581f5 100644 --- a/src/Uno.UWP/Globalization/NumberFormatting/SignificantDigitsNumberRounder.cs +++ b/src/Uno.UWP/Globalization/NumberFormatting/SignificantDigitsNumberRounder.cs @@ -79,7 +79,7 @@ public double RoundDouble(double value) } var integerPart = (int)Math.Truncate(value); - var integerPartLength = (uint)GetIntegerLength(integerPart); + var integerPartLength = (uint)integerPart.GetLength(); var diffLength = SignificantDigits - integerPartLength; if (SignificantDigits < integerPartLength) @@ -94,15 +94,5 @@ public double RoundDouble(double value) return Rounder.Round(value, (int)diffLength, RoundingAlgorithm); } - - private static int GetIntegerLength(int input) - { - if (input == 0) - { - return 1; - } - - return (int)Math.Floor(Math.Log10(Math.Abs(input))) + 1; - } } }