Skip to content

Commit a19da3c

Browse files
committed
Merge branch 'main' into winui
# Conflicts: # CommunityToolkit.Common/Extensions/ISettingsStorageHelperExtensions.cs # CommunityToolkit.Common/Helpers/ObjectStorage/DirectoryItemType.cs # CommunityToolkit.Common/Helpers/ObjectStorage/IFileStorageHelper.cs # CommunityToolkit.Common/Helpers/ObjectStorage/IObjectSerializer.cs # CommunityToolkit.Common/Helpers/ObjectStorage/ISettingsStorageHelper.cs # CommunityToolkit.Common/Helpers/ObjectStorage/SystemSerializer.cs # CommunityToolkit.WinUI.SampleApp/Controls/SampleAppMarkdownRenderer.cs # CommunityToolkit.WinUI.SampleApp/Models/Sample.cs # CommunityToolkit.WinUI.SampleApp/Models/Samples.cs # CommunityToolkit.WinUI.SampleApp/SamplePages/Object Storage/ObjectStoragePage.xaml.cs # CommunityToolkit.WinUI.UI.Controls.Layout/ListDetailsView/ListDetailsView.cs # CommunityToolkit.WinUI/Helpers/ObjectStorage/ApplicationDataStorageHelper.CacheFolder.cs # CommunityToolkit.WinUI/Helpers/ObjectStorage/ApplicationDataStorageHelper.cs # CommunityToolkit.WinUI/Helpers/ObjectStorage/IObjectSerializer.cs # CommunityToolkit.WinUI/Helpers/SystemInformation.cs # UnitTests/UnitTests.UWP/UnitTests.UWP.csproj # azure-pipelines.yml # build/StyleXaml.bat # build/UpdateHeaders.bat # build/build.cake # build/build.ps1
2 parents 0b85891 + 9326ea2 commit a19da3c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+1249
-333
lines changed

.gitattributes

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
#
1818
# Merging from the command prompt will add diff markers to the files if there
1919
# are conflicts (Merging from VS is not affected by the settings below, in VS
20-
# the diff markers are never inserted). Diff markers may cause the following
20+
# the diff markers are never inserted). Diff markers may cause the following
2121
# file extensions to fail to load in VS. An alternative would be to treat
2222
# these files as binary and thus will always conflict and require user
2323
# intervention with every merge. To do so, just uncomment the entries below
@@ -46,9 +46,9 @@
4646

4747
###############################################################################
4848
# diff behavior for common document formats
49-
#
49+
#
5050
# Convert binary document formats to text before diffing them. This feature
51-
# is only available from the command line. Turn it on by uncommenting the
51+
# is only available from the command line. Turn it on by uncommenting the
5252
# entries below.
5353
###############################################################################
5454
#*.doc diff=astextplain

CommunityToolkit.Common/CommunityToolkit.Common.csproj

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,10 @@
2121
<DefineConstants>NETSTANDARD2_1_OR_GREATER</DefineConstants>
2222
</PropertyGroup>
2323

24-
<!-- .NET Standard 1.4 doesn't have the [Pure] attribute -->
24+
<!-- .NET Standard 1.4 doesn't have the [Pure] attribute or ValueTuple -->
2525
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.4'">
2626
<PackageReference Include="System.Diagnostics.Contracts" Version="4.3.0" />
27+
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
2728
</ItemGroup>
2829

2930
</Project>
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Text;
8+
using CommunityToolkit.Common.Helpers;
9+
10+
namespace CommunityToolkit.Common.Extensions
11+
{
12+
/// <summary>
13+
/// Helpers methods for working with <see cref="ISettingsStorageHelper{TKey}"/> implementations.
14+
/// </summary>
15+
public static class ISettingsStorageHelperExtensions
16+
{
17+
/// <summary>
18+
/// Attempts to read the provided key and return the value.
19+
/// If the key is not found, the fallback value will be used instead.
20+
/// </summary>
21+
/// <typeparam name="TKey">The type of key used to lookup the object.</typeparam>
22+
/// <typeparam name="TValue">The type of object value expected.</typeparam>
23+
/// <param name="storageHelper">The storage helper instance fo read from.</param>
24+
/// <param name="key">The key of the target object.</param>
25+
/// <param name="fallback">An alternative value returned if the read fails.</param>
26+
/// <returns>The value of the target object, or the fallback value.</returns>
27+
public static TValue? GetValueOrDefault<TKey, TValue>(this ISettingsStorageHelper<TKey> storageHelper, TKey key, TValue? fallback = default)
28+
where TKey : notnull
29+
{
30+
if (storageHelper.TryRead<TValue>(key, out TValue? storedValue))
31+
{
32+
return storedValue;
33+
}
34+
else
35+
{
36+
return fallback;
37+
}
38+
}
39+
40+
/// <summary>
41+
/// Read the key in the storage helper instance and get the value.
42+
/// </summary>
43+
/// <typeparam name="TKey">The type of key used to lookup the object.</typeparam>
44+
/// <typeparam name="TValue">The type of object value expected.</typeparam>
45+
/// <param name="storageHelper">The storage helper instance fo read from.</param>
46+
/// <param name="key">The key of the target object.</param>
47+
/// <returns>The value of the target object</returns>
48+
/// <exception cref="KeyNotFoundException">Throws when the key is not found in storage.</exception>
49+
public static TValue? Read<TKey, TValue>(this ISettingsStorageHelper<TKey> storageHelper, TKey key)
50+
where TKey : notnull
51+
{
52+
if (storageHelper.TryRead<TValue>(key, out TValue? value))
53+
{
54+
return value;
55+
}
56+
else
57+
{
58+
ThrowKeyNotFoundException(key);
59+
return default;
60+
}
61+
}
62+
63+
/// <summary>
64+
/// Deletes a key from storage.
65+
/// </summary>
66+
/// <typeparam name="TKey">The type of key used to lookup the object.</typeparam>
67+
/// <param name="storageHelper">The storage helper instance to delete from.</param>
68+
/// <param name="key">The key of the target object.</param>
69+
/// <exception cref="KeyNotFoundException">Throws when the key is not found in storage.</exception>
70+
public static void Delete<TKey>(this ISettingsStorageHelper<TKey> storageHelper, TKey key)
71+
where TKey : notnull
72+
{
73+
if (!storageHelper.TryDelete(key))
74+
{
75+
ThrowKeyNotFoundException(key);
76+
}
77+
}
78+
79+
private static void ThrowKeyNotFoundException<TKey>(TKey key)
80+
{
81+
throw new KeyNotFoundException($"The given key '{key}' was not present");
82+
}
83+
}
84+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace CommunityToolkit.Common.Helpers
6+
{
7+
/// <summary>
8+
/// Represents the types of items available in a directory.
9+
/// </summary>
10+
public enum DirectoryItemType
11+
{
12+
/// <summary>
13+
/// The item is neither a file or a folder.
14+
/// </summary>
15+
None,
16+
17+
/// <summary>
18+
/// Represents a file type item.
19+
/// </summary>
20+
File,
21+
22+
/// <summary>
23+
/// Represents a folder type item.
24+
/// </summary>
25+
Folder
26+
}
27+
}
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Collections.Generic;
7+
using System.Threading.Tasks;
8+
9+
namespace CommunityToolkit.Common.Helpers
10+
{
11+
/// <summary>
12+
/// Service interface used to store data in a directory/file-system via files and folders.
13+
///
14+
/// This interface is meant to help abstract file storage operations across platforms in a library,
15+
/// but the actual behavior will be up to the implementer. Such as, we don't provide a sense of a current directory,
16+
/// so an implementor should consider using full paths to support any file operations. Otherwise, a "directory aware"
17+
/// implementation could be achieved with a current directory field and traversal functions, in which case relative paths would be applicable.
18+
/// </summary>
19+
public interface IFileStorageHelper
20+
{
21+
/// <summary>
22+
/// Retrieves an object from a file.
23+
/// </summary>
24+
/// <typeparam name="T">Type of object retrieved.</typeparam>
25+
/// <param name="filePath">Path to the file that contains the object.</param>
26+
/// <param name="default">Default value of the object.</param>
27+
/// <returns>Waiting task until completion with the object in the file.</returns>
28+
Task<T?> ReadFileAsync<T>(string filePath, T? @default = default);
29+
30+
/// <summary>
31+
/// Retrieves the listings for a folder and the item types.
32+
/// </summary>
33+
/// <param name="folderPath">The path to the target folder.</param>
34+
/// <returns>A list of item types and names in the target folder.</returns>
35+
Task<IEnumerable<(DirectoryItemType ItemType, string Name)>> ReadFolderAsync(string folderPath);
36+
37+
/// <summary>
38+
/// Saves an object inside a file.
39+
/// </summary>
40+
/// <typeparam name="T">Type of object saved.</typeparam>
41+
/// <param name="filePath">Path to the file that will contain the object.</param>
42+
/// <param name="value">Object to save.</param>
43+
/// <returns>Waiting task until completion.</returns>
44+
Task CreateFileAsync<T>(string filePath, T value);
45+
46+
/// <summary>
47+
/// Ensure a folder exists at the folder path specified.
48+
/// </summary>
49+
/// <param name="folderPath">The path and name of the target folder.</param>
50+
/// <returns>Waiting task until completion.</returns>
51+
Task CreateFolderAsync(string folderPath);
52+
53+
/// <summary>
54+
/// Deletes a file or folder item.
55+
/// </summary>
56+
/// <param name="itemPath">The path to the item for deletion.</param>
57+
/// <returns>Waiting task until completion.</returns>
58+
Task DeleteItemAsync(string itemPath);
59+
}
60+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
namespace CommunityToolkit.Common.Helpers
6+
{
7+
/// <summary>
8+
/// A basic serialization service.
9+
/// </summary>
10+
public interface IObjectSerializer
11+
{
12+
/// <summary>
13+
/// Serialize an object into a string. It is recommended to use strings as the final format for objects.
14+
/// </summary>
15+
/// <typeparam name="T">The type of the object to serialize.</typeparam>
16+
/// <param name="value">The object to serialize.</param>
17+
/// <returns>The serialized object.</returns>
18+
string? Serialize<T>(T value);
19+
20+
/// <summary>
21+
/// Deserialize string into an object of the given type.
22+
/// </summary>
23+
/// <typeparam name="T">The type of the deserialized object.</typeparam>
24+
/// <param name="value">The string to deserialize.</param>
25+
/// <returns>The deserialized object.</returns>
26+
T Deserialize<T>(string value);
27+
}
28+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System.Collections.Generic;
6+
7+
namespace CommunityToolkit.Common.Helpers
8+
{
9+
/// <summary>
10+
/// Service interface used to store data using key value pairs.
11+
/// </summary>
12+
/// <typeparam name="TKey">The type of keys to use for accessing values.</typeparam>
13+
public interface ISettingsStorageHelper<in TKey>
14+
where TKey : notnull
15+
{
16+
/// <summary>
17+
/// Retrieves a single item by its key.
18+
/// </summary>
19+
/// <typeparam name="TValue">Type of object retrieved.</typeparam>
20+
/// <param name="key">Key of the object.</param>
21+
/// <param name="value">The <see typeparamref="TValue"/> object for <see typeparamref="TKey"/> key.</param>
22+
/// <returns>A boolean indicator of success.</returns>
23+
bool TryRead<TValue>(TKey key, out TValue? value);
24+
25+
/// <summary>
26+
/// Saves a single item by its key.
27+
/// </summary>
28+
/// <typeparam name="TValue">Type of object saved.</typeparam>
29+
/// <param name="key">Key of the value saved.</param>
30+
/// <param name="value">Object to save.</param>
31+
void Save<TValue>(TKey key, TValue value);
32+
33+
/// <summary>
34+
/// Deletes a single item by its key.
35+
/// </summary>
36+
/// <param name="key">Key of the object.</param>
37+
/// <returns>A boolean indicator of success.</returns>
38+
bool TryDelete(TKey key);
39+
40+
/// <summary>
41+
/// Clear all keys and values from the settings store.
42+
/// </summary>
43+
void Clear();
44+
}
45+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
// See the LICENSE file in the project root for more information.
4+
5+
using System;
6+
using System.Reflection;
7+
8+
namespace CommunityToolkit.Common.Helpers
9+
{
10+
/// <summary>
11+
/// A bare-bones serializer which knows how to deal with primitive types and strings only.
12+
/// It is recommended for more complex scenarios to implement your own <see cref="IObjectSerializer"/> based on System.Text.Json, Newtonsoft.Json, or DataContractJsonSerializer see https://aka.ms/wct/storagehelper-migration
13+
/// </summary>
14+
public class SystemSerializer : IObjectSerializer
15+
{
16+
/// <summary>
17+
/// Take a primitive value from storage and return it as the requested type using the <see cref="Convert.ChangeType(object, Type)"/> API.
18+
/// </summary>
19+
/// <typeparam name="T">Type to convert value to.</typeparam>
20+
/// <param name="value">Value from storage to convert.</param>
21+
/// <returns>Deserialized value or default value.</returns>
22+
public T Deserialize<T>(string value)
23+
{
24+
var type = typeof(T);
25+
var typeInfo = type.GetTypeInfo();
26+
27+
if (typeInfo.IsPrimitive || type == typeof(string))
28+
{
29+
return (T)Convert.ChangeType(value, type);
30+
}
31+
32+
throw new NotSupportedException("This serializer can only handle primitive types and strings. Please implement your own IObjectSerializer for more complex scenarios.");
33+
}
34+
35+
/// <summary>
36+
/// Returns the value so that it can be serialized directly.
37+
/// </summary>
38+
/// <typeparam name="T">Type to serialize from.</typeparam>
39+
/// <param name="value">Value to serialize.</param>
40+
/// <returns>String representation of value.</returns>
41+
public string? Serialize<T>(T value)
42+
{
43+
return value?.ToString();
44+
}
45+
}
46+
}

CommunityToolkit.WinUI.SampleApp/Controls/SampleAppMarkdownRenderer.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System;
66
using System.Collections.Generic;
77
using System.Linq;
8+
using CommunityToolkit.Common.Helpers;
89
using CommunityToolkit.Common.Parsers.Markdown;
910
using CommunityToolkit.Common.Parsers.Markdown.Blocks;
1011
using CommunityToolkit.Common.Parsers.Markdown.Inlines;
@@ -407,19 +408,19 @@ public string DesiredLang
407408
{
408409
get
409410
{
410-
return storage.Read<string>(DesiredLangKey);
411+
return settingsStorage.Read<string>(DesiredLangKey);
411412
}
412413

413414
set
414415
{
415-
storage.Save(DesiredLangKey, value);
416+
settingsStorage.Save(DesiredLangKey, value);
416417
}
417418
}
418419

419420
/// <summary>
420-
/// The Local Storage Helper.
421+
/// The local app data storage helper for storing settings.
421422
/// </summary>
422-
private LocalObjectStorageHelper storage = new LocalObjectStorageHelper(new SystemSerializer());
423+
private readonly ApplicationDataStorageHelper settingsStorage = ApplicationDataStorageHelper.GetCurrent();
423424

424425
/// <summary>
425426
/// DocFX note types and styling info, keyed by identifier.

CommunityToolkit.WinUI.SampleApp/Models/Sample.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
// TODO Reintroduce graph controls
2121
// using CommunityToolkit.Graph.Converters;
2222
// using CommunityToolkit.Graph.Providers;
23+
using CommunityToolkit.Common.Helpers;
2324
using CommunityToolkit.WinUI.Helpers;
2425
using CommunityToolkit.WinUI.Input.GazeInteraction;
2526
using CommunityToolkit.WinUI.SampleApp.Models;
@@ -44,7 +45,7 @@ public class Sample
4445

4546
public static async void EnsureCacheLatest()
4647
{
47-
var settingsStorage = new LocalObjectStorageHelper(new SystemSerializer());
48+
var settingsStorage = ApplicationDataStorageHelper.GetCurrent();
4849

4950
var onlineDocsSHA = await GetDocsSHA();
5051
var cacheSHA = settingsStorage.Read<string>(_cacheSHAKey);

0 commit comments

Comments
 (0)