From 09f50c6b573f56b7416072e3abc2b48ddf0c0be9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9s=20Giudici?= Date: Thu, 20 Oct 2022 06:22:56 -0300 Subject: [PATCH 01/77] [Essentials] Fixes IPreferences DateTime handling (#9974) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fixes DateTime values in Preferences (android & UWP) * Fixes DateTime handling for iOS * Fixes tizen PreferencesImplementation to handle DateTime * Adds test for unsupported types * Fixes typo * Fixes casting error * Fixes error * Copies the static Preferences tests to test non-static methods & Updates UWP to use long for DateTime storage Co-authored-by: Andrés Giudici --- .../src/Preferences/Preferences.android.cs | 9 + .../Preferences.ios.tvos.watchos.macos.cs | 11 + .../src/Preferences/Preferences.shared.cs | 25 +- .../src/Preferences/Preferences.tizen.cs | 11 + .../src/Preferences/Preferences.uwp.cs | 22 +- .../DeviceTests/Tests/Preferences_Tests.cs | 233 ++++++++++++++++++ 6 files changed, 307 insertions(+), 4 deletions(-) diff --git a/src/Essentials/src/Preferences/Preferences.android.cs b/src/Essentials/src/Preferences/Preferences.android.cs index c47c1575002b..8e3339504e8a 100644 --- a/src/Essentials/src/Preferences/Preferences.android.cs +++ b/src/Essentials/src/Preferences/Preferences.android.cs @@ -47,6 +47,8 @@ public void Clear(string sharedName) public void Set(string key, T value, string sharedName) { + Preferences.CheckIsSupportedType(); + lock (locker) { using (var sharedPreferences = GetSharedPreferences(sharedName)) @@ -79,6 +81,9 @@ public void Set(string key, T value, string sharedName) case float f: editor.PutFloat(key, f); break; + case DateTime dt: + editor.PutLong(key, dt.ToBinary()); + break; } } editor.Apply(); @@ -134,6 +139,10 @@ public T Get(string key, T defaultValue, string sharedName) // the case when the string is not null value = sharedPreferences.GetString(key, s); break; + case DateTime dt: + var encodedValue = sharedPreferences.GetLong(key, dt.ToBinary()); + value = DateTime.FromBinary(encodedValue); + break; } } } diff --git a/src/Essentials/src/Preferences/Preferences.ios.tvos.watchos.macos.cs b/src/Essentials/src/Preferences/Preferences.ios.tvos.watchos.macos.cs index cc97b54260b0..f932977d8a3a 100644 --- a/src/Essentials/src/Preferences/Preferences.ios.tvos.watchos.macos.cs +++ b/src/Essentials/src/Preferences/Preferences.ios.tvos.watchos.macos.cs @@ -47,6 +47,8 @@ public void Clear(string sharedName) public void Set(string key, T value, string sharedName) { + Preferences.CheckIsSupportedType(); + lock (locker) { using (var userDefaults = GetUserDefaults(sharedName)) @@ -79,6 +81,10 @@ public void Set(string key, T value, string sharedName) case float f: userDefaults.SetFloat(f, key); break; + case DateTime dt: + var encodedDateTime = Convert.ToString(dt.ToBinary(), CultureInfo.InvariantCulture); + userDefaults.SetString(encodedDateTime, key); + break; } } } @@ -113,6 +119,11 @@ public T Get(string key, T defaultValue, string sharedName) case float f: value = userDefaults.FloatForKey(key); break; + case DateTime dt: + var savedDateTime = userDefaults.StringForKey(key); + var encodedDateTime = Convert.ToInt64(savedDateTime, CultureInfo.InvariantCulture); + value = DateTime.FromBinary(encodedDateTime); + break; case string s: // the case when the string is not null value = userDefaults.StringForKey(key); diff --git a/src/Essentials/src/Preferences/Preferences.shared.cs b/src/Essentials/src/Preferences/Preferences.shared.cs index 2baff57c5fc1..0555a1376a49 100644 --- a/src/Essentials/src/Preferences/Preferences.shared.cs +++ b/src/Essentials/src/Preferences/Preferences.shared.cs @@ -1,6 +1,7 @@ #nullable enable using System; using System.Diagnostics.CodeAnalysis; +using System.Linq; namespace Microsoft.Maui.Storage { @@ -162,11 +163,11 @@ public static void Set(string key, DateTime value) => /// public static DateTime Get(string key, DateTime defaultValue, string? sharedName) => - DateTime.FromBinary(Current.Get(key, defaultValue.ToBinary(), sharedName)); + Current.Get(key, defaultValue, sharedName); /// public static void Set(string key, DateTime value, string? sharedName) => - Current.Set(key, value.ToBinary(), sharedName); + Current.Set(key, value, sharedName); static IPreferences Current => Storage.Preferences.Default; @@ -180,5 +181,25 @@ internal static string GetPrivatePreferencesSharedName(string feature) => internal static void SetDefault(IPreferences? implementation) => defaultImplementation = implementation; + + internal static Type[] SupportedTypes = new Type[] + { + typeof(string), + typeof(int), + typeof(bool), + typeof(long), + typeof(double), + typeof(float), + typeof(DateTime), + }; + + internal static void CheckIsSupportedType() + { + var type = typeof(T); + if (!SupportedTypes.Contains(type)) + { + throw new NotSupportedException($"Preferences using '{type}' type is not supported"); + } + } } } diff --git a/src/Essentials/src/Preferences/Preferences.tizen.cs b/src/Essentials/src/Preferences/Preferences.tizen.cs index 48b522733886..24331afb8ed8 100644 --- a/src/Essentials/src/Preferences/Preferences.tizen.cs +++ b/src/Essentials/src/Preferences/Preferences.tizen.cs @@ -1,3 +1,4 @@ +using System; using System.Linq; using Tizen.Applications; @@ -46,11 +47,17 @@ public void Clear(string sharedName) public void Set(string key, T value, string sharedName) { + Preferences.CheckIsSupportedType(); + lock (locker) { var fullKey = GetFullKey(key, sharedName); if (value == null) Preference.Remove(fullKey); + else if (value is DateTime dt) + { + Preference.Set(fullKey, dt.ToBinary()); + } else Preference.Set(fullKey, value); } @@ -74,6 +81,10 @@ public T Get(string key, T defaultValue, string sharedName) case string s: value = Preference.Get(fullKey); break; + case DateTime dt: + var encodedValue = Preference.Get(fullKey); + value = (T)(object)DateTime.FromBinary(encodedValue); + break; default: // the case when the string is null if (typeof(T) == typeof(string)) diff --git a/src/Essentials/src/Preferences/Preferences.uwp.cs b/src/Essentials/src/Preferences/Preferences.uwp.cs index 4ee7f21b10e9..b6c6a7706beb 100644 --- a/src/Essentials/src/Preferences/Preferences.uwp.cs +++ b/src/Essentials/src/Preferences/Preferences.uwp.cs @@ -71,6 +71,8 @@ public void Clear(string sharedName) public void Set(string key, T value, string sharedName) { + Preferences.CheckIsSupportedType(); + lock (locker) { var appDataContainer = GetApplicationDataContainer(sharedName); @@ -82,7 +84,14 @@ public void Set(string key, T value, string sharedName) return; } - appDataContainer.Values[key] = value; + if (value is DateTime dt) + { + appDataContainer.Values[key] = dt.ToBinary(); + } + else + { + appDataContainer.Values[key] = value; + } } } @@ -95,7 +104,16 @@ public T Get(string key, T defaultValue, string sharedName) { var tempValue = appDataContainer.Values[key]; if (tempValue != null) - return (T)tempValue; + { + if (defaultValue is DateTime dt) + { + return (T)(object)DateTime.FromBinary((long)tempValue); + } + else + { + return (T)tempValue; + } + } } } diff --git a/src/Essentials/test/DeviceTests/Tests/Preferences_Tests.cs b/src/Essentials/test/DeviceTests/Tests/Preferences_Tests.cs index ddd07fe1fdc9..cf628cff602c 100644 --- a/src/Essentials/test/DeviceTests/Tests/Preferences_Tests.cs +++ b/src/Essentials/test/DeviceTests/Tests/Preferences_Tests.cs @@ -13,6 +13,7 @@ public class Preferences_Tests static DateTime testDateTime = new DateTime(2018, 05, 07); + #region Static method tests [Theory] [InlineData("datetime1", null)] [InlineData("datetime1", sharedNameTestData)] @@ -235,5 +236,237 @@ public void DateTimePreservesKind(string sharedName, DateTimeKind kind) Assert.Equal(date, get); Assert.Equal(kind, get.Kind); } + + #endregion + + #region Non-static method tests + + [Fact] + public void FailsWithUnsupportedType() => + Assert.Throws(() => Preferences.Default.Set("anything", new int[] { 1 })); + + [Theory] + [InlineData("datetime1", null)] + [InlineData("datetime1", sharedNameTestData)] + public void Set_Get_DateTime_NonStatic(string key, string sharedName) + { + Preferences.Default.Set(key, testDateTime, sharedName); + + Assert.Equal(testDateTime, Preferences.Default.Get(key, DateTime.MinValue, sharedName)); + } + + [Theory] + [InlineData("string1", "TEST", null)] + [InlineData("string1", "TEST", sharedNameTestData)] + public void Set_Get_String_NonStatic(string key, string value, string sharedName) + { + Preferences.Default.Set(key, value, sharedName); + + Assert.Equal(value, Preferences.Default.Get(key, null, sharedName)); + } + + [Theory] + [InlineData("string1", "TEST", null)] + [InlineData("string1", "TEST", sharedNameTestData)] + public void Set_Set_Null_Get_String_NonStatic(string key, string value, string sharedName) + { + Preferences.Default.Set(key, value, sharedName); + Preferences.Default.Set(key, null, sharedName); + + Assert.Null(Preferences.Default.Get(key, null, sharedName)); + } + + [Theory] + [InlineData("int1", int.MaxValue - 1, null)] + [InlineData("sint1", int.MinValue + 1, null)] + [InlineData("int1", int.MaxValue - 1, sharedNameTestData)] + [InlineData("sint1", int.MinValue + 1, sharedNameTestData)] + public void Set_Get_Int_NonStatic(string key, int value, string sharedName) + { + Preferences.Default.Set(key, value, sharedName); + Assert.Equal(value, Preferences.Default.Get(key, 0, sharedName)); + } + + [Theory] + [InlineData("long1", long.MaxValue - 1, null)] + [InlineData("slong1", long.MinValue + 1, null)] + [InlineData("long1", long.MaxValue - 1, sharedNameTestData)] + [InlineData("slong1", long.MinValue + 1, sharedNameTestData)] + public void Set_Get_Long_NonStatic(string key, long value, string sharedName) + { + Preferences.Default.Set(key, value, sharedName); + Assert.Equal(value, Preferences.Default.Get(key, 0L, sharedName)); + } + + [Theory] + [InlineData("float1", float.MaxValue - 1, null)] + [InlineData("sfloat1", float.MinValue + 1, null)] + [InlineData("float1", float.MaxValue - 1, sharedNameTestData)] + [InlineData("sfloat1", float.MinValue + 1, sharedNameTestData)] + public void Set_Get_Float_NonStatic(string key, float value, string sharedName) + { + Preferences.Default.Set(key, value, sharedName); + Assert.Equal(value, Preferences.Default.Get(key, 0f, sharedName)); + } + + [Theory] + [InlineData("double1", double.MaxValue - 1, null)] + [InlineData("sdouble1", double.MinValue + 1, null)] + [InlineData("double1", double.MaxValue - 1, sharedNameTestData)] + [InlineData("sdouble1", double.MinValue + 1, sharedNameTestData)] + public void Set_Get_Double_NonStatic(string key, double value, string sharedName) + { + Preferences.Default.Set(key, value, sharedName); + Assert.Equal(value, Preferences.Default.Get(key, 0d, sharedName)); + } + + [Theory] + [InlineData("bool1", true, null)] + [InlineData("bool1", true, sharedNameTestData)] + public void Set_Get_Bool_NonStatic(string key, bool value, string sharedName) + { + Preferences.Default.Set(key, value, sharedName); + Assert.Equal(value, Preferences.Default.Get(key, false, sharedName)); + } + + [Theory] + [InlineData(null)] + [InlineData(sharedNameTestData)] + public void Remove_NonStatic(string sharedName) + { + Preferences.Default.Set("RemoveKey1", "value", sharedName); + + Assert.Equal("value", Preferences.Default.Get("RemoveKey1", null, sharedName)); + + Preferences.Default.Remove("RemoveKey1", sharedName); + + Assert.Null(Preferences.Default.Get("RemoveKey1", null, sharedName)); + } + + [Theory] + [InlineData(null, true)] + [InlineData(sharedNameTestData, true)] + [InlineData(null, false)] + [InlineData(sharedNameTestData, false)] + public void Remove_Get_Bool_NonStatic(string sharedName, bool defaultValue) + { + Preferences.Default.Remove("RemoveGetKey1", sharedName); + + Assert.Equal(defaultValue, Preferences.Default.Get("RemoveGetKey1", defaultValue, sharedName)); + } + + [Theory] + [InlineData(null, 5)] + [InlineData(sharedNameTestData, 5)] + [InlineData(null, 0)] + [InlineData(sharedNameTestData, 0)] + public void Remove_Get_Double_NonStatic(string sharedName, double defaultValue) + { + Preferences.Default.Remove("RemoveGetKey1", sharedName); + + Assert.Equal(defaultValue, Preferences.Default.Get("RemoveGetKey1", defaultValue, sharedName)); + } + + [Theory] + [InlineData(null, 5)] + [InlineData(sharedNameTestData, 5)] + [InlineData(null, 0)] + [InlineData(sharedNameTestData, 0)] + public void Remove_Get_Float_NonStatic(string sharedName, float defaultValue) + { + Preferences.Default.Remove("RemoveGetKey1", sharedName); + + Assert.Equal(defaultValue, Preferences.Default.Get("RemoveGetKey1", defaultValue, sharedName)); + } + + [Theory] + [InlineData(null, 5)] + [InlineData(sharedNameTestData, 5)] + [InlineData(null, 0)] + [InlineData(sharedNameTestData, 0)] + public void Remove_Get_Int_NonStatic(string sharedName, int defaultValue) + { + Preferences.Default.Remove("RemoveGetKey1", sharedName); + + Assert.Equal(defaultValue, Preferences.Default.Get("RemoveGetKey1", defaultValue, sharedName)); + } + + [Theory] + [InlineData(null, 5)] + [InlineData(sharedNameTestData, 5)] + [InlineData(null, 0)] + [InlineData(sharedNameTestData, 0)] + public void Remove_Get_Long_NonStatic(string sharedName, long defaultValue) + { + Preferences.Default.Remove("RemoveGetKey1", sharedName); + + Assert.Equal(defaultValue, Preferences.Default.Get("RemoveGetKey1", defaultValue, sharedName)); + } + + [Theory] + [InlineData(null, "text")] + [InlineData(sharedNameTestData, "text")] + [InlineData(null, null)] + [InlineData(sharedNameTestData, null)] + public void Remove_Get_String_NonStatic(string sharedName, string defaultValue) + { + Preferences.Default.Remove("RemoveGetKey1", sharedName); + + Assert.Equal(defaultValue, Preferences.Default.Get("RemoveGetKey1", defaultValue, sharedName)); + } + + [Theory] + [InlineData(null)] + [InlineData(sharedNameTestData)] + public void Clear_NonStatic(string sharedName) + { + Preferences.Default.Set("ClearKey1", "value", sharedName); + Preferences.Default.Set("ClearKey2", 2, sharedName); + + Assert.Equal(2, Preferences.Default.Get("ClearKey2", 0, sharedName)); + + Preferences.Default.Clear(sharedName); + + Assert.NotEqual("value", Preferences.Default.Get("ClearKey1", null, sharedName)); + Assert.NotEqual(2, Preferences.Default.Get("ClearKey2", 0, sharedName)); + } + + [Theory] + [InlineData(null)] + [InlineData(sharedNameTestData)] + public void Does_ContainsKey_NonStatic(string sharedName) + { + Preferences.Default.Set("DoesContainsKey1", "One", sharedName); + + Assert.True(Preferences.Default.ContainsKey("DoesContainsKey1", sharedName)); + } + + [Theory] + [InlineData(null)] + [InlineData(sharedNameTestData)] + public void Not_ContainsKey_NonStatic(string sharedName) + { + Preferences.Default.Remove("NotContainsKey1", sharedName); + + Assert.False(Preferences.Default.ContainsKey("NotContainsKey1", sharedName)); + } + + [Theory] + [InlineData(null, DateTimeKind.Utc)] + [InlineData(sharedNameTestData, DateTimeKind.Utc)] + [InlineData(null, DateTimeKind.Local)] + [InlineData(sharedNameTestData, DateTimeKind.Local)] + public void DateTimePreservesKind_NonStatic(string sharedName, DateTimeKind kind) + { + var date = new DateTime(2018, 05, 07, 8, 30, 0, kind); + + Preferences.Default.Set("datetime_utc", date, sharedName); + + var get = Preferences.Default.Get("datetime_utc", DateTime.MinValue, sharedName); + + Assert.Equal(date, get); + Assert.Equal(kind, get.Kind); + } + #endregion } } From 3b576a75087e67c73b9838134fd5a0521c5ce296 Mon Sep 17 00:00:00 2001 From: Samantha Houts Date: Thu, 20 Oct 2022 02:39:02 -0700 Subject: [PATCH 02/77] Fix more comment/docs typos (#10796) This is definitely for ease of reviewing and not at all for artificially increasing my PR count. --- .../ButtonDisabledStatesGallery.xaml | 2 +- .../DatePickerDisabledStatesGallery.xaml | 2 +- .../EditorDisabledStatesGallery.xaml | 2 +- .../EntryDisabledStatesGallery.xaml | 2 +- .../PickerDisabledStatesGallery.xaml | 2 +- .../SearchBarDisabledStatesGallery.xaml | 2 +- .../TimePickerDisabledStatesGallery.xaml | 2 +- .../Core/src/Android/StepperRendererManager.cs | 4 ++-- src/Controls/docs/Microsoft.Maui.Controls/BaseMenuItem.xml | 2 +- src/Controls/src/Core/IPinchGestureController.cs | 2 +- .../Core.UnitTests/MarshalingObservableCollectionTests.cs | 2 +- src/Core/src/Platform/Android/ContextExtensions.cs | 2 +- .../Platform/Android/Navigation/NavigationViewFragment.cs | 2 +- .../Platform/Android/Navigation/StackNavigationManager.cs | 6 +++--- src/Core/src/Platform/Android/StepperHandlerManager.cs | 4 ++-- 15 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/Compatibility/ControlGallery/src/Core/GalleryPages/VisualStateManagerGalleries/ButtonDisabledStatesGallery.xaml b/src/Compatibility/ControlGallery/src/Core/GalleryPages/VisualStateManagerGalleries/ButtonDisabledStatesGallery.xaml index 93fe6aa26a29..63dfae7f4c4d 100644 --- a/src/Compatibility/ControlGallery/src/Core/GalleryPages/VisualStateManagerGalleries/ButtonDisabledStatesGallery.xaml +++ b/src/Compatibility/ControlGallery/src/Core/GalleryPages/VisualStateManagerGalleries/ButtonDisabledStatesGallery.xaml @@ -76,7 +76,7 @@