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
This commit is contained in:
Коммит
a19da3c409
|
@ -21,9 +21,10 @@
|
|||
<DefineConstants>NETSTANDARD2_1_OR_GREATER</DefineConstants>
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- .NET Standard 1.4 doesn't have the [Pure] attribute -->
|
||||
<!-- .NET Standard 1.4 doesn't have the [Pure] attribute or ValueTuple -->
|
||||
<ItemGroup Condition="'$(TargetFramework)' == 'netstandard1.4'">
|
||||
<PackageReference Include="System.Diagnostics.Contracts" Version="4.3.0" />
|
||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,84 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using CommunityToolkit.Common.Helpers;
|
||||
|
||||
namespace CommunityToolkit.Common.Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Helpers methods for working with <see cref="ISettingsStorageHelper{TKey}"/> implementations.
|
||||
/// </summary>
|
||||
public static class ISettingsStorageHelperExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Attempts to read the provided key and return the value.
|
||||
/// If the key is not found, the fallback value will be used instead.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">The type of key used to lookup the object.</typeparam>
|
||||
/// <typeparam name="TValue">The type of object value expected.</typeparam>
|
||||
/// <param name="storageHelper">The storage helper instance fo read from.</param>
|
||||
/// <param name="key">The key of the target object.</param>
|
||||
/// <param name="fallback">An alternative value returned if the read fails.</param>
|
||||
/// <returns>The value of the target object, or the fallback value.</returns>
|
||||
public static TValue? GetValueOrDefault<TKey, TValue>(this ISettingsStorageHelper<TKey> storageHelper, TKey key, TValue? fallback = default)
|
||||
where TKey : notnull
|
||||
{
|
||||
if (storageHelper.TryRead<TValue>(key, out TValue? storedValue))
|
||||
{
|
||||
return storedValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
return fallback;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Read the key in the storage helper instance and get the value.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">The type of key used to lookup the object.</typeparam>
|
||||
/// <typeparam name="TValue">The type of object value expected.</typeparam>
|
||||
/// <param name="storageHelper">The storage helper instance fo read from.</param>
|
||||
/// <param name="key">The key of the target object.</param>
|
||||
/// <returns>The value of the target object</returns>
|
||||
/// <exception cref="KeyNotFoundException">Throws when the key is not found in storage.</exception>
|
||||
public static TValue? Read<TKey, TValue>(this ISettingsStorageHelper<TKey> storageHelper, TKey key)
|
||||
where TKey : notnull
|
||||
{
|
||||
if (storageHelper.TryRead<TValue>(key, out TValue? value))
|
||||
{
|
||||
return value;
|
||||
}
|
||||
else
|
||||
{
|
||||
ThrowKeyNotFoundException(key);
|
||||
return default;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a key from storage.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">The type of key used to lookup the object.</typeparam>
|
||||
/// <param name="storageHelper">The storage helper instance to delete from.</param>
|
||||
/// <param name="key">The key of the target object.</param>
|
||||
/// <exception cref="KeyNotFoundException">Throws when the key is not found in storage.</exception>
|
||||
public static void Delete<TKey>(this ISettingsStorageHelper<TKey> storageHelper, TKey key)
|
||||
where TKey : notnull
|
||||
{
|
||||
if (!storageHelper.TryDelete(key))
|
||||
{
|
||||
ThrowKeyNotFoundException(key);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ThrowKeyNotFoundException<TKey>(TKey key)
|
||||
{
|
||||
throw new KeyNotFoundException($"The given key '{key}' was not present");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace CommunityToolkit.Common.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the types of items available in a directory.
|
||||
/// </summary>
|
||||
public enum DirectoryItemType
|
||||
{
|
||||
/// <summary>
|
||||
/// The item is neither a file or a folder.
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// Represents a file type item.
|
||||
/// </summary>
|
||||
File,
|
||||
|
||||
/// <summary>
|
||||
/// Represents a folder type item.
|
||||
/// </summary>
|
||||
Folder
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace CommunityToolkit.Common.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Service interface used to store data in a directory/file-system via files and folders.
|
||||
///
|
||||
/// This interface is meant to help abstract file storage operations across platforms in a library,
|
||||
/// but the actual behavior will be up to the implementer. Such as, we don't provide a sense of a current directory,
|
||||
/// so an implementor should consider using full paths to support any file operations. Otherwise, a "directory aware"
|
||||
/// implementation could be achieved with a current directory field and traversal functions, in which case relative paths would be applicable.
|
||||
/// </summary>
|
||||
public interface IFileStorageHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves an object from a file.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object retrieved.</typeparam>
|
||||
/// <param name="filePath">Path to the file that contains the object.</param>
|
||||
/// <param name="default">Default value of the object.</param>
|
||||
/// <returns>Waiting task until completion with the object in the file.</returns>
|
||||
Task<T?> ReadFileAsync<T>(string filePath, T? @default = default);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the listings for a folder and the item types.
|
||||
/// </summary>
|
||||
/// <param name="folderPath">The path to the target folder.</param>
|
||||
/// <returns>A list of item types and names in the target folder.</returns>
|
||||
Task<IEnumerable<(DirectoryItemType ItemType, string Name)>> ReadFolderAsync(string folderPath);
|
||||
|
||||
/// <summary>
|
||||
/// Saves an object inside a file.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object saved.</typeparam>
|
||||
/// <param name="filePath">Path to the file that will contain the object.</param>
|
||||
/// <param name="value">Object to save.</param>
|
||||
/// <returns>Waiting task until completion.</returns>
|
||||
Task CreateFileAsync<T>(string filePath, T value);
|
||||
|
||||
/// <summary>
|
||||
/// Ensure a folder exists at the folder path specified.
|
||||
/// </summary>
|
||||
/// <param name="folderPath">The path and name of the target folder.</param>
|
||||
/// <returns>Waiting task until completion.</returns>
|
||||
Task CreateFolderAsync(string folderPath);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a file or folder item.
|
||||
/// </summary>
|
||||
/// <param name="itemPath">The path to the item for deletion.</param>
|
||||
/// <returns>Waiting task until completion.</returns>
|
||||
Task DeleteItemAsync(string itemPath);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace CommunityToolkit.Common.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// A basic serialization service.
|
||||
/// </summary>
|
||||
public interface IObjectSerializer
|
||||
{
|
||||
/// <summary>
|
||||
/// Serialize an object into a string. It is recommended to use strings as the final format for objects.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the object to serialize.</typeparam>
|
||||
/// <param name="value">The object to serialize.</param>
|
||||
/// <returns>The serialized object.</returns>
|
||||
string? Serialize<T>(T value);
|
||||
|
||||
/// <summary>
|
||||
/// Deserialize string into an object of the given type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the deserialized object.</typeparam>
|
||||
/// <param name="value">The string to deserialize.</param>
|
||||
/// <returns>The deserialized object.</returns>
|
||||
T Deserialize<T>(string value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace CommunityToolkit.Common.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Service interface used to store data using key value pairs.
|
||||
/// </summary>
|
||||
/// <typeparam name="TKey">The type of keys to use for accessing values.</typeparam>
|
||||
public interface ISettingsStorageHelper<in TKey>
|
||||
where TKey : notnull
|
||||
{
|
||||
/// <summary>
|
||||
/// Retrieves a single item by its key.
|
||||
/// </summary>
|
||||
/// <typeparam name="TValue">Type of object retrieved.</typeparam>
|
||||
/// <param name="key">Key of the object.</param>
|
||||
/// <param name="value">The <see typeparamref="TValue"/> object for <see typeparamref="TKey"/> key.</param>
|
||||
/// <returns>A boolean indicator of success.</returns>
|
||||
bool TryRead<TValue>(TKey key, out TValue? value);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a single item by its key.
|
||||
/// </summary>
|
||||
/// <typeparam name="TValue">Type of object saved.</typeparam>
|
||||
/// <param name="key">Key of the value saved.</param>
|
||||
/// <param name="value">Object to save.</param>
|
||||
void Save<TValue>(TKey key, TValue value);
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a single item by its key.
|
||||
/// </summary>
|
||||
/// <param name="key">Key of the object.</param>
|
||||
/// <returns>A boolean indicator of success.</returns>
|
||||
bool TryDelete(TKey key);
|
||||
|
||||
/// <summary>
|
||||
/// Clear all keys and values from the settings store.
|
||||
/// </summary>
|
||||
void Clear();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
|
||||
namespace CommunityToolkit.Common.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// A bare-bones serializer which knows how to deal with primitive types and strings only.
|
||||
/// 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
|
||||
/// </summary>
|
||||
public class SystemSerializer : IObjectSerializer
|
||||
{
|
||||
/// <summary>
|
||||
/// Take a primitive value from storage and return it as the requested type using the <see cref="Convert.ChangeType(object, Type)"/> API.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type to convert value to.</typeparam>
|
||||
/// <param name="value">Value from storage to convert.</param>
|
||||
/// <returns>Deserialized value or default value.</returns>
|
||||
public T Deserialize<T>(string value)
|
||||
{
|
||||
var type = typeof(T);
|
||||
var typeInfo = type.GetTypeInfo();
|
||||
|
||||
if (typeInfo.IsPrimitive || type == typeof(string))
|
||||
{
|
||||
return (T)Convert.ChangeType(value, type);
|
||||
}
|
||||
|
||||
throw new NotSupportedException("This serializer can only handle primitive types and strings. Please implement your own IObjectSerializer for more complex scenarios.");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the value so that it can be serialized directly.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type to serialize from.</typeparam>
|
||||
/// <param name="value">Value to serialize.</param>
|
||||
/// <returns>String representation of value.</returns>
|
||||
public string? Serialize<T>(T value)
|
||||
{
|
||||
return value?.ToString();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using CommunityToolkit.Common.Helpers;
|
||||
using CommunityToolkit.Common.Parsers.Markdown;
|
||||
using CommunityToolkit.Common.Parsers.Markdown.Blocks;
|
||||
using CommunityToolkit.Common.Parsers.Markdown.Inlines;
|
||||
|
@ -407,19 +408,19 @@ namespace CommunityToolkit.WinUI.SampleApp.Controls
|
|||
{
|
||||
get
|
||||
{
|
||||
return storage.Read<string>(DesiredLangKey);
|
||||
return settingsStorage.Read<string>(DesiredLangKey);
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
storage.Save(DesiredLangKey, value);
|
||||
settingsStorage.Save(DesiredLangKey, value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The Local Storage Helper.
|
||||
/// The local app data storage helper for storing settings.
|
||||
/// </summary>
|
||||
private LocalObjectStorageHelper storage = new LocalObjectStorageHelper(new SystemSerializer());
|
||||
private readonly ApplicationDataStorageHelper settingsStorage = ApplicationDataStorageHelper.GetCurrent();
|
||||
|
||||
/// <summary>
|
||||
/// DocFX note types and styling info, keyed by identifier.
|
||||
|
|
|
@ -20,6 +20,7 @@ using System.Threading.Tasks;
|
|||
// TODO Reintroduce graph controls
|
||||
// using CommunityToolkit.Graph.Converters;
|
||||
// using CommunityToolkit.Graph.Providers;
|
||||
using CommunityToolkit.Common.Helpers;
|
||||
using CommunityToolkit.WinUI.Helpers;
|
||||
using CommunityToolkit.WinUI.Input.GazeInteraction;
|
||||
using CommunityToolkit.WinUI.SampleApp.Models;
|
||||
|
@ -44,7 +45,7 @@ namespace CommunityToolkit.WinUI.SampleApp
|
|||
|
||||
public static async void EnsureCacheLatest()
|
||||
{
|
||||
var settingsStorage = new LocalObjectStorageHelper(new SystemSerializer());
|
||||
var settingsStorage = ApplicationDataStorageHelper.GetCurrent();
|
||||
|
||||
var onlineDocsSHA = await GetDocsSHA();
|
||||
var cacheSHA = settingsStorage.Read<string>(_cacheSHAKey);
|
||||
|
|
|
@ -10,8 +10,8 @@ using System.Linq;
|
|||
using System.Text.Json;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Common.Helpers;
|
||||
using CommunityToolkit.WinUI.Helpers;
|
||||
using Windows.ApplicationModel;
|
||||
|
||||
namespace CommunityToolkit.WinUI.SampleApp
|
||||
{
|
||||
|
@ -23,7 +23,7 @@ namespace CommunityToolkit.WinUI.SampleApp
|
|||
private static SemaphoreSlim _semaphore = new SemaphoreSlim(1);
|
||||
|
||||
private static LinkedList<Sample> _recentSamples;
|
||||
private static LocalObjectStorageHelper _localObjectStorageHelper = new LocalObjectStorageHelper(new SystemSerializer());
|
||||
private static ApplicationDataStorageHelper _settingsStorage = ApplicationDataStorageHelper.GetCurrent();
|
||||
|
||||
public static async Task<SampleCategory> GetCategoryBySample(Sample sample)
|
||||
{
|
||||
|
@ -129,7 +129,7 @@ namespace CommunityToolkit.WinUI.SampleApp
|
|||
if (_recentSamples == null)
|
||||
{
|
||||
_recentSamples = new LinkedList<Sample>();
|
||||
var savedSamples = _localObjectStorageHelper.Read<string>(_recentSamplesStorageKey);
|
||||
var savedSamples = _settingsStorage.Read<string>(_recentSamplesStorageKey);
|
||||
|
||||
if (savedSamples != null)
|
||||
{
|
||||
|
@ -175,7 +175,7 @@ namespace CommunityToolkit.WinUI.SampleApp
|
|||
}
|
||||
|
||||
var str = string.Join(";", _recentSamples.Take(10).Select(s => s.Name).ToArray());
|
||||
_localObjectStorageHelper.Save<string>(_recentSamplesStorageKey, str);
|
||||
_settingsStorage.Save<string>(_recentSamplesStorageKey, str);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -74,9 +74,9 @@
|
|||
</controls:ListDetailsView.NoSelectionContentTemplate>
|
||||
<controls:ListDetailsView.ListCommandBar>
|
||||
<CommandBar>
|
||||
<!-- Button functionality to be implemented by developer -->
|
||||
<AppBarButton Icon="Back" Label="Back"/>
|
||||
<AppBarButton Icon="Forward" Label="Forward"/>
|
||||
|
||||
<CommandBar.Content>
|
||||
<TextBlock Margin="12,14">
|
||||
<Run Text="{Binding Emails.Count}" />
|
||||
|
@ -87,6 +87,7 @@
|
|||
</controls:ListDetailsView.ListCommandBar>
|
||||
<controls:ListDetailsView.DetailsCommandBar>
|
||||
<CommandBar>
|
||||
<!-- Button functionality to be implemented by developer -->
|
||||
<AppBarButton Icon="MailReply" Label="Reply" />
|
||||
<AppBarButton Icon="MailReplyAll" Label="Reply All" />
|
||||
<AppBarButton Icon="MailForward" Label="Forward" />
|
||||
|
|
|
@ -1,25 +1,24 @@
|
|||
var localObjectStorageHelper = new LocalObjectStorageHelper();
|
||||
var roamingObjectStorageHelper = new RoamingObjectStorageHelper();
|
||||
ApplicationDataStorageHelper appDataStorageHelper = ApplicationDataStorageHelper.GetCurrent(new CommunityToolkit.Common.Helpers.SystemSerializer());
|
||||
|
||||
// Read and Save with simple objects
|
||||
string keySimpleObject = "simple";
|
||||
string result = localObjectStorageHelper.Read<string>(keySimpleObject);
|
||||
localObjectStorageHelper.Save(keySimpleObject, 47);
|
||||
string result = appDataStorageHelper.Read<string>(keySimpleObject);
|
||||
appDataStorageHelper.Save(keySimpleObject, 47);
|
||||
|
||||
// Read and Save with complex/large objects
|
||||
string keyLargeObject = "large";
|
||||
var result = localObjectStorageHelper.ReadFileAsync<MyLargeObject>(keyLargeObject);
|
||||
string complexObjectKey = "complexObject";
|
||||
var complexObject = await appDataStorageHelper.ReadFileAsync<MyLargeObject>(complexObjectKey);
|
||||
|
||||
var o = new MyLargeObject
|
||||
var myComplexObject = new MyComplexObject()
|
||||
{
|
||||
...
|
||||
};
|
||||
localObjectStorageHelper.SaveFileAsync(keySimpleObject, o);
|
||||
await appDataStorageHelper.SaveFileAsync(complexObjectKey, myComplexObject);
|
||||
|
||||
// Complex object
|
||||
public class MyLargeObject
|
||||
public class MyComplexObject
|
||||
{
|
||||
public string MyContent { get; set; }
|
||||
public List<string> MyContents { get; set; }
|
||||
public List<MyLargeObject> MyObjects { get; set; }
|
||||
public List<MyComplexObject> MyObjects { get; set; }
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using CommunityToolkit.Common.Helpers;
|
||||
using CommunityToolkit.WinUI.Helpers;
|
||||
using Microsoft.UI.Xaml;
|
||||
|
||||
|
@ -9,7 +10,7 @@ namespace CommunityToolkit.WinUI.SampleApp.SamplePages
|
|||
{
|
||||
public sealed partial class ObjectStoragePage
|
||||
{
|
||||
private readonly IObjectStorageHelper localStorageHelper = new LocalObjectStorageHelper(new SystemSerializer());
|
||||
private readonly ApplicationDataStorageHelper _settingsStorage = ApplicationDataStorageHelper.GetCurrent();
|
||||
|
||||
public ObjectStoragePage()
|
||||
{
|
||||
|
@ -24,9 +25,9 @@ namespace CommunityToolkit.WinUI.SampleApp.SamplePages
|
|||
}
|
||||
|
||||
// Read from local storage
|
||||
if (localStorageHelper.KeyExists(KeyTextBox.Text))
|
||||
if (_settingsStorage.KeyExists(KeyTextBox.Text))
|
||||
{
|
||||
ContentTextBox.Text = localStorageHelper.Read<string>(KeyTextBox.Text);
|
||||
ContentTextBox.Text = _settingsStorage.Read<string>(KeyTextBox.Text);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -43,7 +44,7 @@ namespace CommunityToolkit.WinUI.SampleApp.SamplePages
|
|||
}
|
||||
|
||||
// Save into local storage
|
||||
localStorageHelper.Save(KeyTextBox.Text, ContentTextBox.Text);
|
||||
_settingsStorage.Save(KeyTextBox.Text, ContentTextBox.Text);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ using Microsoft.UI.Xaml.Input;
|
|||
using Microsoft.UI.Xaml.Navigation;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.UI.Core;
|
||||
using NavigationView = Microsoft.UI.Xaml.Controls;
|
||||
|
||||
namespace CommunityToolkit.WinUI.UI.Controls
|
||||
{
|
||||
|
@ -42,12 +43,11 @@ namespace CommunityToolkit.WinUI.UI.Controls
|
|||
private AppViewBackButtonVisibility? _previousSystemBackButtonVisibility;
|
||||
private bool _previousNavigationViewBackEnabled;
|
||||
|
||||
// Int used because the underlying type is an enum, but we don't have access to the enum
|
||||
private int _previousNavigationViewBackVisibilty;
|
||||
private NavigationView.NavigationViewBackButtonVisible _previousNavigationViewBackVisibilty;
|
||||
private NavigationView.NavigationView _navigationView;
|
||||
private ContentPresenter _detailsPresenter;
|
||||
private VisualStateGroup _selectionStateGroup;
|
||||
private Button _inlineBackButton;
|
||||
private object _navigationView;
|
||||
private Frame _frame;
|
||||
|
||||
/// <summary>
|
||||
|
@ -203,7 +203,7 @@ namespace CommunityToolkit.WinUI.UI.Controls
|
|||
_frame.Navigating -= OnFrameNavigating;
|
||||
}
|
||||
|
||||
_navigationView = this.FindAscendants().FirstOrDefault(p => p.GetType().FullName == "Microsoft.UI.Xaml.Controls.NavigationView");
|
||||
_navigationView = this.FindAscendant<NavigationView.NavigationView>();
|
||||
_frame = this.FindAscendant<Frame>();
|
||||
if (_frame != null)
|
||||
{
|
||||
|
@ -336,8 +336,6 @@ namespace CommunityToolkit.WinUI.UI.Controls
|
|||
/// </summary>
|
||||
private void SetBackButtonVisibility(ListDetailsViewState? previousState = null)
|
||||
{
|
||||
const int backButtonVisible = 1;
|
||||
|
||||
if (DesignMode.DesignModeEnabled)
|
||||
{
|
||||
return;
|
||||
|
@ -368,7 +366,7 @@ namespace CommunityToolkit.WinUI.UI.Controls
|
|||
}
|
||||
else
|
||||
{
|
||||
SetNavigationViewBackButtonState(backButtonVisible, true);
|
||||
SetNavigationViewBackButtonState(NavigationView.NavigationViewBackButtonVisible.Visible, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -458,27 +456,18 @@ namespace CommunityToolkit.WinUI.UI.Controls
|
|||
VisualStateManager.GoToState(this, SelectedItem == null ? noSelectionState : hasSelectionState, animate);
|
||||
}
|
||||
|
||||
private void SetNavigationViewBackButtonState(int visible, bool enabled)
|
||||
private void SetNavigationViewBackButtonState(NavigationView.NavigationViewBackButtonVisible visibility, bool enabled)
|
||||
{
|
||||
if (_navigationView == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var navType = _navigationView.GetType();
|
||||
var visibleProperty = navType.GetProperty("IsBackButtonVisible");
|
||||
if (visibleProperty != null)
|
||||
{
|
||||
_previousNavigationViewBackVisibilty = (int)visibleProperty.GetValue(_navigationView);
|
||||
visibleProperty.SetValue(_navigationView, visible);
|
||||
}
|
||||
_previousNavigationViewBackVisibilty = _navigationView.IsBackButtonVisible;
|
||||
_navigationView.IsBackButtonVisible = visibility;
|
||||
|
||||
var enabledProperty = navType.GetProperty("IsBackEnabled");
|
||||
if (enabledProperty != null)
|
||||
{
|
||||
_previousNavigationViewBackEnabled = (bool)enabledProperty.GetValue(_navigationView);
|
||||
enabledProperty.SetValue(_navigationView, enabled);
|
||||
}
|
||||
_previousNavigationViewBackEnabled = _navigationView.IsBackEnabled;
|
||||
_navigationView.IsBackEnabled = enabled;
|
||||
}
|
||||
|
||||
private void SetDetailsContent()
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Common.Helpers;
|
||||
using Windows.Storage;
|
||||
|
||||
namespace CommunityToolkit.WinUI.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// An extension of ApplicationDataStorageHelper with additional features for interop with the LocalCacheFolder.
|
||||
/// </summary>
|
||||
public partial class ApplicationDataStorageHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the local cache folder.
|
||||
/// </summary>
|
||||
public StorageFolder CacheFolder => AppData.LocalCacheFolder;
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves an object from a file in the LocalCacheFolder.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object retrieved.</typeparam>
|
||||
/// <param name="filePath">Path to the file that contains the object.</param>
|
||||
/// <param name="default">Default value of the object.</param>
|
||||
/// <returns>Waiting task until completion with the object in the file.</returns>
|
||||
public Task<T> ReadCacheFileAsync<T>(string filePath, T @default = default)
|
||||
{
|
||||
return ReadFileAsync<T>(CacheFolder, filePath, @default);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves the listings for a folder and the item types in the LocalCacheFolder.
|
||||
/// </summary>
|
||||
/// <param name="folderPath">The path to the target folder.</param>
|
||||
/// <returns>A list of file types and names in the target folder.</returns>
|
||||
public Task<IEnumerable<(DirectoryItemType ItemType, string Name)>> ReadCacheFolderAsync(string folderPath)
|
||||
{
|
||||
return ReadFolderAsync(CacheFolder, folderPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves an object inside a file in the LocalCacheFolder.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object saved.</typeparam>
|
||||
/// <param name="filePath">Path to the file that will contain the object.</param>
|
||||
/// <param name="value">Object to save.</param>
|
||||
/// <returns>Waiting task until completion.</returns>
|
||||
public Task CreateCacheFileAsync<T>(string filePath, T value)
|
||||
{
|
||||
return SaveFileAsync<T>(CacheFolder, filePath, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ensure a folder exists at the folder path specified in the LocalCacheFolder.
|
||||
/// </summary>
|
||||
/// <param name="folderPath">The path and name of the target folder.</param>
|
||||
/// <returns>Waiting task until completion.</returns>
|
||||
public Task CreateCacheFolderAsync(string folderPath)
|
||||
{
|
||||
return CreateFolderAsync(CacheFolder, folderPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a file or folder item in the LocalCacheFolder.
|
||||
/// </summary>
|
||||
/// <param name="itemPath">The path to the item for deletion.</param>
|
||||
/// <returns>Waiting task until completion.</returns>
|
||||
public Task DeleteCacheItemAsync(string itemPath)
|
||||
{
|
||||
return DeleteItemAsync(CacheFolder, itemPath);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,326 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Common.Helpers;
|
||||
using Windows.Storage;
|
||||
using Windows.System;
|
||||
|
||||
#nullable enable
|
||||
|
||||
namespace CommunityToolkit.WinUI.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Storage helper for files and folders living in Windows.Storage.ApplicationData storage endpoints.
|
||||
/// </summary>
|
||||
public partial class ApplicationDataStorageHelper : IFileStorageHelper, ISettingsStorageHelper<string>
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ApplicationDataStorageHelper"/> class.
|
||||
/// </summary>
|
||||
/// <param name="appData">The data store to interact with.</param>
|
||||
/// <param name="objectSerializer">Serializer for converting stored values. Defaults to <see cref="Common.Helpers.SystemSerializer"/>.</param>
|
||||
public ApplicationDataStorageHelper(ApplicationData appData, Common.Helpers.IObjectSerializer? objectSerializer = null)
|
||||
{
|
||||
this.AppData = appData ?? throw new ArgumentNullException(nameof(appData));
|
||||
this.Serializer = objectSerializer ?? new Common.Helpers.SystemSerializer();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the settings container.
|
||||
/// </summary>
|
||||
public ApplicationDataContainer Settings => this.AppData.LocalSettings;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the storage folder.
|
||||
/// </summary>
|
||||
public StorageFolder Folder => this.AppData.LocalFolder;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the storage host.
|
||||
/// </summary>
|
||||
protected ApplicationData AppData { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the serializer for converting stored values.
|
||||
/// </summary>
|
||||
protected Common.Helpers.IObjectSerializer Serializer { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Get a new instance using ApplicationData.Current and the provided serializer.
|
||||
/// </summary>
|
||||
/// <param name="objectSerializer">Serializer for converting stored values. Defaults to <see cref="Common.Helpers.SystemSerializer"/>.</param>
|
||||
/// <returns>A new instance of ApplicationDataStorageHelper.</returns>
|
||||
public static ApplicationDataStorageHelper GetCurrent(Common.Helpers.IObjectSerializer? objectSerializer = null)
|
||||
{
|
||||
var appData = ApplicationData.Current;
|
||||
return new ApplicationDataStorageHelper(appData, objectSerializer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a new instance using the ApplicationData for the provided user and serializer.
|
||||
/// </summary>
|
||||
/// <param name="user">App data user owner.</param>
|
||||
/// <param name="objectSerializer">Serializer for converting stored values. Defaults to <see cref="Common.Helpers.SystemSerializer"/>.</param>
|
||||
/// <returns>A new instance of ApplicationDataStorageHelper.</returns>
|
||||
public static async Task<ApplicationDataStorageHelper> GetForUserAsync(User user, Common.Helpers.IObjectSerializer? objectSerializer = null)
|
||||
{
|
||||
var appData = await ApplicationData.GetForUserAsync(user);
|
||||
return new ApplicationDataStorageHelper(appData, objectSerializer);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a setting already exists.
|
||||
/// </summary>
|
||||
/// <param name="key">Key of the setting (that contains object).</param>
|
||||
/// <returns>True if a value exists.</returns>
|
||||
public bool KeyExists(string key)
|
||||
{
|
||||
return this.Settings.Values.ContainsKey(key);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a single item by its key.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object retrieved.</typeparam>
|
||||
/// <param name="key">Key of the object.</param>
|
||||
/// <param name="default">Default value of the object.</param>
|
||||
/// <returns>The TValue object.</returns>
|
||||
public T? Read<T>(string key, T? @default = default)
|
||||
{
|
||||
if (this.Settings.Values.TryGetValue(key, out var valueObj) && valueObj is string valueString)
|
||||
{
|
||||
return this.Serializer.Deserialize<T>(valueString);
|
||||
}
|
||||
|
||||
return @default;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool TryRead<T>(string key, out T? value)
|
||||
{
|
||||
if (this.Settings.Values.TryGetValue(key, out var valueObj) && valueObj is string valueString)
|
||||
{
|
||||
value = this.Serializer.Deserialize<T>(valueString);
|
||||
return true;
|
||||
}
|
||||
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Save<T>(string key, T value)
|
||||
{
|
||||
this.Settings.Values[key] = this.Serializer.Serialize(value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool TryDelete(string key)
|
||||
{
|
||||
return this.Settings.Values.Remove(key);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Clear()
|
||||
{
|
||||
this.Settings.Values.Clear();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a setting already exists in composite.
|
||||
/// </summary>
|
||||
/// <param name="compositeKey">Key of the composite (that contains settings).</param>
|
||||
/// <param name="key">Key of the setting (that contains object).</param>
|
||||
/// <returns>True if a value exists.</returns>
|
||||
public bool KeyExists(string compositeKey, string key)
|
||||
{
|
||||
if (this.TryRead(compositeKey, out ApplicationDataCompositeValue? composite) && composite != null)
|
||||
{
|
||||
return composite.ContainsKey(key);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to retrieve a single item by its key in composite.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object retrieved.</typeparam>
|
||||
/// <param name="compositeKey">Key of the composite (that contains settings).</param>
|
||||
/// <param name="key">Key of the object.</param>
|
||||
/// <param name="value">The value of the object retrieved.</param>
|
||||
/// <returns>The T object.</returns>
|
||||
public bool TryRead<T>(string compositeKey, string key, out T? value)
|
||||
{
|
||||
if (this.TryRead(compositeKey, out ApplicationDataCompositeValue? composite) && composite != null)
|
||||
{
|
||||
string compositeValue = (string)composite[key];
|
||||
if (compositeValue != null)
|
||||
{
|
||||
value = this.Serializer.Deserialize<T>(compositeValue);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
value = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a single item by its key in composite.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object retrieved.</typeparam>
|
||||
/// <param name="compositeKey">Key of the composite (that contains settings).</param>
|
||||
/// <param name="key">Key of the object.</param>
|
||||
/// <param name="default">Default value of the object.</param>
|
||||
/// <returns>The T object.</returns>
|
||||
public T? Read<T>(string compositeKey, string key, T? @default = default)
|
||||
{
|
||||
if (this.TryRead(compositeKey, out ApplicationDataCompositeValue? composite) && composite != null)
|
||||
{
|
||||
if (composite.TryGetValue(key, out object valueObj) && valueObj is string value)
|
||||
{
|
||||
return this.Serializer.Deserialize<T>(value);
|
||||
}
|
||||
}
|
||||
|
||||
return @default;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a group of items by its key in a composite.
|
||||
/// This method should be considered for objects that do not exceed 8k bytes during the lifetime of the application
|
||||
/// and for groups of settings which need to be treated in an atomic way.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object saved.</typeparam>
|
||||
/// <param name="compositeKey">Key of the composite (that contains settings).</param>
|
||||
/// <param name="values">Objects to save.</param>
|
||||
public void Save<T>(string compositeKey, IDictionary<string, T> values)
|
||||
{
|
||||
if (this.TryRead(compositeKey, out ApplicationDataCompositeValue? composite) && composite != null)
|
||||
{
|
||||
foreach (KeyValuePair<string, T> setting in values)
|
||||
{
|
||||
if (composite.ContainsKey(setting.Key))
|
||||
{
|
||||
composite[setting.Key] = this.Serializer.Serialize(setting.Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
composite.Add(setting.Key, this.Serializer.Serialize(setting.Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
composite = new ApplicationDataCompositeValue();
|
||||
foreach (KeyValuePair<string, T> setting in values)
|
||||
{
|
||||
composite.Add(setting.Key, this.Serializer.Serialize(setting.Value));
|
||||
}
|
||||
|
||||
this.Settings.Values[compositeKey] = composite;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Deletes a single item by its key in composite.
|
||||
/// </summary>
|
||||
/// <param name="compositeKey">Key of the composite (that contains settings).</param>
|
||||
/// <param name="key">Key of the object.</param>
|
||||
/// <returns>A boolean indicator of success.</returns>
|
||||
public bool TryDelete(string compositeKey, string key)
|
||||
{
|
||||
if (this.TryRead(compositeKey, out ApplicationDataCompositeValue? composite) && composite != null)
|
||||
{
|
||||
return composite.Remove(key);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<T?> ReadFileAsync<T>(string filePath, T? @default = default)
|
||||
{
|
||||
return this.ReadFileAsync<T>(this.Folder, filePath, @default);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<IEnumerable<(DirectoryItemType ItemType, string Name)>> ReadFolderAsync(string folderPath)
|
||||
{
|
||||
return this.ReadFolderAsync(this.Folder, folderPath);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task CreateFileAsync<T>(string filePath, T value)
|
||||
{
|
||||
return this.SaveFileAsync<T>(this.Folder, filePath, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task CreateFolderAsync(string folderPath)
|
||||
{
|
||||
return this.CreateFolderAsync(this.Folder, folderPath);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task DeleteItemAsync(string itemPath)
|
||||
{
|
||||
return this.DeleteItemAsync(this.Folder, itemPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves an object inside a file.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object saved.</typeparam>
|
||||
/// <param name="filePath">Path to the file that will contain the object.</param>
|
||||
/// <param name="value">Object to save.</param>
|
||||
/// <returns>Waiting task until completion.</returns>
|
||||
public Task<StorageFile> SaveFileAsync<T>(string filePath, T value)
|
||||
{
|
||||
return this.SaveFileAsync(this.Folder, filePath, value);
|
||||
}
|
||||
|
||||
private async Task<T?> ReadFileAsync<T>(StorageFolder folder, string filePath, T? @default = default)
|
||||
{
|
||||
string value = await StorageFileHelper.ReadTextFromFileAsync(folder, filePath);
|
||||
return (value != null) ? this.Serializer.Deserialize<T>(value) : @default;
|
||||
}
|
||||
|
||||
private async Task<IEnumerable<(DirectoryItemType, string)>> ReadFolderAsync(StorageFolder folder, string folderPath)
|
||||
{
|
||||
var targetFolder = await folder.GetFolderAsync(folderPath);
|
||||
var items = await targetFolder.GetItemsAsync();
|
||||
|
||||
return items.Select((item) =>
|
||||
{
|
||||
var itemType = item.IsOfType(StorageItemTypes.File) ? DirectoryItemType.File
|
||||
: item.IsOfType(StorageItemTypes.Folder) ? DirectoryItemType.Folder
|
||||
: DirectoryItemType.None;
|
||||
|
||||
return (itemType, item.Name);
|
||||
});
|
||||
}
|
||||
|
||||
private Task<StorageFile> SaveFileAsync<T>(StorageFolder folder, string filePath, T value)
|
||||
{
|
||||
return StorageFileHelper.WriteTextToFileAsync(folder, this.Serializer.Serialize(value)?.ToString(), filePath, CreationCollisionOption.ReplaceExisting);
|
||||
}
|
||||
|
||||
private async Task CreateFolderAsync(StorageFolder folder, string folderPath)
|
||||
{
|
||||
await folder.CreateFolderAsync(folderPath, CreationCollisionOption.OpenIfExists);
|
||||
}
|
||||
|
||||
private async Task DeleteItemAsync(StorageFolder folder, string itemPath)
|
||||
{
|
||||
var item = await folder.GetItemAsync(itemPath);
|
||||
await item.DeleteAsync();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ namespace CommunityToolkit.WinUI.Helpers
|
|||
/// <summary>
|
||||
/// Shared implementation of ObjectStorageHelper.
|
||||
/// </summary>
|
||||
[Obsolete("BaseObjectStorageHelper is deprecated and has been superceded by ApplicationDataStorageHelper.")]
|
||||
public abstract class BaseObjectStorageHelper : IObjectStorageHelper
|
||||
{
|
||||
private readonly IObjectSerializer serializer;
|
||||
|
|
|
@ -2,11 +2,14 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
|
||||
namespace CommunityToolkit.WinUI.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// A basic serialization service.
|
||||
/// </summary>
|
||||
[Obsolete("IObjectSerializer has been migrated to the Microsoft.Toolkit (CommunityToolkit.Common) package.")]
|
||||
public interface IObjectSerializer
|
||||
{
|
||||
/// <summary>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.Storage;
|
||||
|
@ -11,48 +12,49 @@ namespace CommunityToolkit.WinUI.Helpers
|
|||
/// <summary>
|
||||
/// Service used to store data.
|
||||
/// </summary>
|
||||
[Obsolete("IObjectStorageHelper is deprecated. Please use ISettingsStorageHelper and IFileStorageHelper interfaces instead.")]
|
||||
public interface IObjectStorageHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines whether a setting already exists.
|
||||
/// </summary>
|
||||
/// <param name="key">Key of the setting (that contains object)</param>
|
||||
/// <returns>True if a value exists</returns>
|
||||
/// <param name="key">Key of the setting (that contains object).</param>
|
||||
/// <returns>True if a value exists.</returns>
|
||||
bool KeyExists(string key);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a setting already exists in composite.
|
||||
/// </summary>
|
||||
/// <param name="compositeKey">Key of the composite (that contains settings)</param>
|
||||
/// <param name="key">Key of the setting (that contains object)</param>
|
||||
/// <returns>True if a value exists</returns>
|
||||
/// <param name="compositeKey">Key of the composite (that contains settings).</param>
|
||||
/// <param name="key">Key of the setting (that contains object).</param>
|
||||
/// <returns>True if a value exists.</returns>
|
||||
bool KeyExists(string compositeKey, string key);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a single item by its key.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object retrieved</typeparam>
|
||||
/// <param name="key">Key of the object</param>
|
||||
/// <param name="default">Default value of the object</param>
|
||||
/// <returns>The T object</returns>
|
||||
T Read<T>(string key, T @default = default(T));
|
||||
/// <typeparam name="T">Type of object retrieved.</typeparam>
|
||||
/// <param name="key">Key of the object.</param>
|
||||
/// <param name="default">Default value of the object.</param>
|
||||
/// <returns>The T object.</returns>
|
||||
T Read<T>(string key, T @default = default);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves a single item by its key in composite.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object retrieved</typeparam>
|
||||
/// <param name="compositeKey">Key of the composite (that contains settings)</param>
|
||||
/// <param name="key">Key of the object</param>
|
||||
/// <param name="default">Default value of the object</param>
|
||||
/// <returns>The T object</returns>
|
||||
T Read<T>(string compositeKey, string key, T @default = default(T));
|
||||
/// <typeparam name="T">Type of object retrieved.</typeparam>
|
||||
/// <param name="compositeKey">Key of the composite (that contains settings).</param>
|
||||
/// <param name="key">Key of the object.</param>
|
||||
/// <param name="default">Default value of the object.</param>
|
||||
/// <returns>The T object.</returns>
|
||||
T Read<T>(string compositeKey, string key, T @default = default);
|
||||
|
||||
/// <summary>
|
||||
/// Saves a single item by its key.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object saved</typeparam>
|
||||
/// <param name="key">Key of the value saved</param>
|
||||
/// <param name="value">Object to save</param>
|
||||
/// <typeparam name="T">Type of object saved.</typeparam>
|
||||
/// <param name="key">Key of the value saved.</param>
|
||||
/// <param name="value">Object to save.</param>
|
||||
void Save<T>(string key, T value);
|
||||
|
||||
/// <summary>
|
||||
|
@ -61,34 +63,34 @@ namespace CommunityToolkit.WinUI.Helpers
|
|||
/// (refers to <see cref="SaveFileAsync{T}(string, T)"/> for complex/large objects) and for groups of settings which
|
||||
/// need to be treated in an atomic way.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object saved</typeparam>
|
||||
/// <param name="compositeKey">Key of the composite (that contains settings)</param>
|
||||
/// <param name="values">Objects to save</param>
|
||||
/// <typeparam name="T">Type of object saved.</typeparam>
|
||||
/// <param name="compositeKey">Key of the composite (that contains settings).</param>
|
||||
/// <param name="values">Objects to save.</param>
|
||||
void Save<T>(string compositeKey, IDictionary<string, T> values);
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a file already exists.
|
||||
/// </summary>
|
||||
/// <param name="filePath">Key of the file (that contains object)</param>
|
||||
/// <returns>True if a value exists</returns>
|
||||
/// <param name="filePath">Key of the file (that contains object).</param>
|
||||
/// <returns>True if a value exists.</returns>
|
||||
Task<bool> FileExistsAsync(string filePath);
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves an object from a file.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object retrieved</typeparam>
|
||||
/// <param name="filePath">Path to the file that contains the object</param>
|
||||
/// <param name="default">Default value of the object</param>
|
||||
/// <returns>Waiting task until completion with the object in the file</returns>
|
||||
Task<T> ReadFileAsync<T>(string filePath, T @default = default(T));
|
||||
/// <typeparam name="T">Type of object retrieved.</typeparam>
|
||||
/// <param name="filePath">Path to the file that contains the object.</param>
|
||||
/// <param name="default">Default value of the object.</param>
|
||||
/// <returns>Waiting task until completion with the object in the file.</returns>
|
||||
Task<T> ReadFileAsync<T>(string filePath, T @default = default);
|
||||
|
||||
/// <summary>
|
||||
/// Saves an object inside a file.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of object saved</typeparam>
|
||||
/// <param name="filePath">Path to the file that will contain the object</param>
|
||||
/// <param name="value">Object to save</param>
|
||||
/// <returns>Waiting task until completion</returns>
|
||||
/// <typeparam name="T">Type of object saved.</typeparam>
|
||||
/// <param name="filePath">Path to the file that will contain the object.</param>
|
||||
/// <param name="value">Object to save.</param>
|
||||
/// <returns>Waiting task until completion.</returns>
|
||||
Task<StorageFile> SaveFileAsync<T>(string filePath, T value);
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@
|
|||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using Windows.Storage;
|
||||
|
||||
namespace CommunityToolkit.WinUI.Helpers
|
||||
|
@ -9,20 +10,21 @@ namespace CommunityToolkit.WinUI.Helpers
|
|||
/// <summary>
|
||||
/// Store data in the Local environment (only on the current device).
|
||||
/// </summary>
|
||||
[Obsolete("LocalObjectStorageHelper is deprecated and has been superceded by the ApplicationDataStorageHelper. To upgrade, simply swap any LocalObjectStorageHelper instances with ApplicationDataStorageHelper.GetCurrent(serializer). The underlying interfaces are nearly identical but now with even more features available, such as deletion and access to user specific data stores!")]
|
||||
public class LocalObjectStorageHelper : BaseObjectStorageHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LocalObjectStorageHelper"/> class,
|
||||
/// which can read and write data using the provided <see cref="IObjectSerializer"/>;
|
||||
/// In 6.1 and older the default Serializer was based on Newtonsoft.Json.
|
||||
/// To implement an <see cref="IObjectSerializer"/> based on System.Text.Json, Newtonsoft.Json, or DataContractJsonSerializer see https://aka.ms/wct/storagehelper-migration
|
||||
/// To implement an <see cref="IObjectSerializer"/> based on System.Text.Json, Newtonsoft.Json, or DataContractJsonSerializer see https://aka.ms/wct/storagehelper-migration.
|
||||
/// </summary>
|
||||
/// <param name="objectSerializer">The serializer to use.</param>
|
||||
public LocalObjectStorageHelper(IObjectSerializer objectSerializer)
|
||||
: base(objectSerializer)
|
||||
{
|
||||
Settings = ApplicationData.Current.LocalSettings;
|
||||
Folder = ApplicationData.Current.LocalFolder;
|
||||
this.Settings = ApplicationData.Current.LocalSettings;
|
||||
this.Folder = ApplicationData.Current.LocalFolder;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,6 +12,7 @@ namespace CommunityToolkit.WinUI.Helpers
|
|||
/// A bare-bones serializer which knows how to deal with primitive types and strings only. It will store them directly based on the <see cref="ApplicationDataContainer"/> API.
|
||||
/// 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
|
||||
/// </summary>
|
||||
[Obsolete("SystemSerializer has been migrated to the Microsoft.Toolkit (CommunityToolkit.Common) package.")]
|
||||
public class SystemSerializer : IObjectSerializer
|
||||
{
|
||||
/// <summary>
|
||||
|
|
|
@ -6,6 +6,7 @@ using System;
|
|||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Common.Helpers;
|
||||
using Microsoft.UI.Xaml;
|
||||
using Windows.ApplicationModel;
|
||||
using Windows.ApplicationModel.Activation;
|
||||
|
@ -23,9 +24,9 @@ namespace CommunityToolkit.WinUI.Helpers
|
|||
public sealed class SystemInformation
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="LocalObjectStorageHelper"/> instance used to save and retrieve application settings.
|
||||
/// The <see cref="ApplicationDataStorageHelper"/> instance used to save and retrieve application settings.
|
||||
/// </summary>
|
||||
private readonly LocalObjectStorageHelper _localObjectStorageHelper = new(new SystemSerializer());
|
||||
private readonly ApplicationDataStorageHelper _settingsStorage = ApplicationDataStorageHelper.GetCurrent();
|
||||
|
||||
/// <summary>
|
||||
/// The starting time of the current application session (since app launch or last move to foreground).
|
||||
|
@ -216,7 +217,7 @@ namespace CommunityToolkit.WinUI.Helpers
|
|||
if (LaunchCount > 0)
|
||||
{
|
||||
var subSessionLength = DateTime.UtcNow.Subtract(_sessionStart).Ticks;
|
||||
var uptimeSoFar = _localObjectStorageHelper.Read<long>(nameof(AppUptime));
|
||||
var uptimeSoFar = _settingsStorage.Read<long>(nameof(AppUptime));
|
||||
|
||||
return new(uptimeSoFar + subSessionLength);
|
||||
}
|
||||
|
@ -232,9 +233,9 @@ namespace CommunityToolkit.WinUI.Helpers
|
|||
/// <param name="duration">The amount to time to add</param>
|
||||
public void AddToAppUptime(TimeSpan duration)
|
||||
{
|
||||
var uptimeSoFar = _localObjectStorageHelper.Read<long>(nameof(AppUptime));
|
||||
var uptimeSoFar = _settingsStorage.Read<long>(nameof(AppUptime));
|
||||
|
||||
_localObjectStorageHelper.Save(nameof(AppUptime), uptimeSoFar + duration.Ticks);
|
||||
_settingsStorage.Save(nameof(AppUptime), uptimeSoFar + duration.Ticks);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -245,8 +246,8 @@ namespace CommunityToolkit.WinUI.Helpers
|
|||
LastResetTime = DateTime.UtcNow;
|
||||
LaunchCount = 0;
|
||||
|
||||
_localObjectStorageHelper.Save(nameof(LastResetTime), LastResetTime.ToFileTimeUtc());
|
||||
_localObjectStorageHelper.Save(nameof(LaunchCount), LaunchCount);
|
||||
_settingsStorage.Save(nameof(LastResetTime), LastResetTime.ToFileTimeUtc());
|
||||
_settingsStorage.Save(nameof(LaunchCount), LaunchCount);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -258,8 +259,8 @@ namespace CommunityToolkit.WinUI.Helpers
|
|||
{
|
||||
if (args.PreviousExecutionState is ApplicationExecutionState.ClosedByUser or ApplicationExecutionState.NotRunning)
|
||||
{
|
||||
LaunchCount = _localObjectStorageHelper.Read<long>(nameof(LaunchCount)) + 1;
|
||||
TotalLaunchCount = _localObjectStorageHelper.Read<long>(nameof(TotalLaunchCount)) + 1;
|
||||
LaunchCount = _settingsStorage.Read<long>(nameof(LaunchCount)) + 1;
|
||||
TotalLaunchCount = _settingsStorage.Read<long>(nameof(TotalLaunchCount)) + 1;
|
||||
|
||||
// In case we upgraded the properties, make TotalLaunchCount is correct
|
||||
if (TotalLaunchCount < LaunchCount)
|
||||
|
@ -267,21 +268,21 @@ namespace CommunityToolkit.WinUI.Helpers
|
|||
TotalLaunchCount = LaunchCount;
|
||||
}
|
||||
|
||||
_localObjectStorageHelper.Save(nameof(LaunchCount), LaunchCount);
|
||||
_localObjectStorageHelper.Save(nameof(TotalLaunchCount), TotalLaunchCount);
|
||||
_settingsStorage.Save(nameof(LaunchCount), LaunchCount);
|
||||
_settingsStorage.Save(nameof(TotalLaunchCount), TotalLaunchCount);
|
||||
|
||||
LaunchTime = DateTime.UtcNow;
|
||||
|
||||
var lastLaunch = _localObjectStorageHelper.Read<long>(nameof(LastLaunchTime));
|
||||
var lastLaunch = _settingsStorage.Read<long>(nameof(LastLaunchTime));
|
||||
|
||||
LastLaunchTime = lastLaunch != 0
|
||||
? DateTime.FromFileTimeUtc(lastLaunch)
|
||||
: LaunchTime;
|
||||
|
||||
_localObjectStorageHelper.Save(nameof(LastLaunchTime), LaunchTime.ToFileTimeUtc());
|
||||
_localObjectStorageHelper.Save(nameof(AppUptime), 0L);
|
||||
_settingsStorage.Save(nameof(LastLaunchTime), LaunchTime.ToFileTimeUtc());
|
||||
_settingsStorage.Save(nameof(AppUptime), 0L);
|
||||
|
||||
var lastResetTime = _localObjectStorageHelper.Read<long>(nameof(LastResetTime));
|
||||
var lastResetTime = _settingsStorage.Read<long>(nameof(LastResetTime));
|
||||
|
||||
LastResetTime = lastResetTime != 0
|
||||
? DateTime.FromFileTimeUtc(lastResetTime)
|
||||
|
@ -323,20 +324,20 @@ namespace CommunityToolkit.WinUI.Helpers
|
|||
else
|
||||
{
|
||||
var subSessionLength = DateTime.UtcNow.Subtract(_sessionStart).Ticks;
|
||||
var uptimeSoFar = _localObjectStorageHelper.Read<long>(nameof(AppUptime));
|
||||
var uptimeSoFar = _settingsStorage.Read<long>(nameof(AppUptime));
|
||||
|
||||
_localObjectStorageHelper.Save(nameof(AppUptime), uptimeSoFar + subSessionLength);
|
||||
_settingsStorage.Save(nameof(AppUptime), uptimeSoFar + subSessionLength);
|
||||
}
|
||||
}
|
||||
|
||||
private bool DetectIfFirstUse()
|
||||
{
|
||||
if (_localObjectStorageHelper.KeyExists(nameof(IsFirstRun)))
|
||||
if (_settingsStorage.KeyExists(nameof(IsFirstRun)))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_localObjectStorageHelper.Save(nameof(IsFirstRun), true);
|
||||
_settingsStorage.Save(nameof(IsFirstRun), true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -349,13 +350,13 @@ namespace CommunityToolkit.WinUI.Helpers
|
|||
// is ever called. That is, this is either the first time the app has been launched, or the first
|
||||
// time a previously existing app has run this method (or has run it after a new update of the app).
|
||||
// In this case, save the current version and report the same version as previous version installed.
|
||||
if (!_localObjectStorageHelper.KeyExists(nameof(currentVersion)))
|
||||
if (!_settingsStorage.KeyExists(nameof(currentVersion)))
|
||||
{
|
||||
_localObjectStorageHelper.Save(nameof(currentVersion), currentVersion);
|
||||
_settingsStorage.Save(nameof(currentVersion), currentVersion);
|
||||
}
|
||||
else
|
||||
{
|
||||
var previousVersion = _localObjectStorageHelper.Read<string>(nameof(currentVersion));
|
||||
var previousVersion = _settingsStorage.Read<string>(nameof(currentVersion));
|
||||
|
||||
// There are two possible cases if the "currentVersion" key exists:
|
||||
// 1) The previous version is different than the current one. This means that the application
|
||||
|
@ -365,7 +366,7 @@ namespace CommunityToolkit.WinUI.Helpers
|
|||
// In this case we have nothing to do and just return the previous version installed to be the same.
|
||||
if (currentVersion != previousVersion)
|
||||
{
|
||||
_localObjectStorageHelper.Save(nameof(currentVersion), currentVersion);
|
||||
_settingsStorage.Save(nameof(currentVersion), currentVersion);
|
||||
|
||||
return (true, previousVersion.ToPackageVersion());
|
||||
}
|
||||
|
@ -376,28 +377,28 @@ namespace CommunityToolkit.WinUI.Helpers
|
|||
|
||||
private DateTime DetectFirstUseTime()
|
||||
{
|
||||
if (_localObjectStorageHelper.KeyExists(nameof(FirstUseTime)))
|
||||
if (_settingsStorage.KeyExists(nameof(FirstUseTime)))
|
||||
{
|
||||
var firstUse = _localObjectStorageHelper.Read<long>(nameof(FirstUseTime));
|
||||
var firstUse = _settingsStorage.Read<long>(nameof(FirstUseTime));
|
||||
|
||||
return DateTime.FromFileTimeUtc(firstUse);
|
||||
}
|
||||
|
||||
DateTime utcNow = DateTime.UtcNow;
|
||||
|
||||
_localObjectStorageHelper.Save(nameof(FirstUseTime), utcNow.ToFileTimeUtc());
|
||||
_settingsStorage.Save(nameof(FirstUseTime), utcNow.ToFileTimeUtc());
|
||||
|
||||
return utcNow;
|
||||
}
|
||||
|
||||
private PackageVersion DetectFirstVersionInstalled()
|
||||
{
|
||||
if (_localObjectStorageHelper.KeyExists(nameof(FirstVersionInstalled)))
|
||||
if (_settingsStorage.KeyExists(nameof(FirstVersionInstalled)))
|
||||
{
|
||||
return _localObjectStorageHelper.Read<string>(nameof(FirstVersionInstalled)).ToPackageVersion();
|
||||
return _settingsStorage.Read<string>(nameof(FirstVersionInstalled)).ToPackageVersion();
|
||||
}
|
||||
|
||||
_localObjectStorageHelper.Save(nameof(FirstVersionInstalled), ApplicationVersion.ToFormattedString());
|
||||
_settingsStorage.Save(nameof(FirstVersionInstalled), ApplicationVersion.ToFormattedString());
|
||||
|
||||
return ApplicationVersion;
|
||||
}
|
||||
|
|
|
@ -7,11 +7,13 @@ using System.Reflection;
|
|||
using CommunityToolkit.WinUI.Helpers;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace UnitTests.UWP.Helpers
|
||||
namespace UnitTests.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a Serializer which should mimic the previous functionality of 6.1.1 release of the Toolkit with Newtonsoft.Json.
|
||||
/// Based on <see cref="Microsoft.Toolkit.Uwp.Helpers.IObjectSerializer"/>.
|
||||
/// </summary>
|
||||
[Obsolete]
|
||||
internal class JsonObjectSerializer : IObjectSerializer
|
||||
{
|
||||
public T Deserialize<T>(object value)
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using Microsoft.Toolkit.Helpers;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
namespace UnitTests.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// This is a Serializer which should mimic the previous functionality of 6.1.1 release of the Toolkit with Newtonsoft.Json.
|
||||
/// Based on <see cref="Microsoft.Toolkit.Helpers.IObjectSerializer"/>.
|
||||
/// </summary>
|
||||
internal class JsonObjectSerializer2 : IObjectSerializer
|
||||
{
|
||||
public T Deserialize<T>(string value)
|
||||
{
|
||||
var type = typeof(T);
|
||||
var typeInfo = type.GetTypeInfo();
|
||||
|
||||
// Note: If you're creating a new app, you could just use the serializer directly.
|
||||
// This if/return combo is to maintain compatibility with 6.1.1
|
||||
if (typeInfo.IsPrimitive || type == typeof(string))
|
||||
{
|
||||
return (T)Convert.ChangeType(value, type);
|
||||
}
|
||||
|
||||
return JsonConvert.DeserializeObject<T>(value);
|
||||
}
|
||||
|
||||
public string Serialize<T>(T value)
|
||||
{
|
||||
var type = typeof(T);
|
||||
var typeInfo = type.GetTypeInfo();
|
||||
|
||||
// Note: If you're creating a new app, you could just use the serializer directly.
|
||||
// This if/return combo is to maintain compatibility with 6.1.1
|
||||
if (typeInfo.IsPrimitive || type == typeof(string))
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
|
||||
return JsonConvert.SerializeObject(value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,11 +6,13 @@ using System;
|
|||
using System.Text.Json;
|
||||
using CommunityToolkit.WinUI.Helpers;
|
||||
|
||||
namespace UnitTests.UWP.Helpers
|
||||
namespace UnitTests.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Example class of writing a new <see cref="IObjectSerializer"/> that uses System.Text.Json.
|
||||
/// Based on <see cref="Microsoft.Toolkit.Uwp.Helpers.IObjectSerializer"/>.
|
||||
/// </summary>
|
||||
[Obsolete]
|
||||
internal class SystemTextJsonSerializer : IObjectSerializer
|
||||
{
|
||||
public T Deserialize<T>(object value) => JsonSerializer.Deserialize<T>(value as string);
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System.Text.Json;
|
||||
using Microsoft.Toolkit.Helpers;
|
||||
|
||||
namespace UnitTests.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Example class of writing a new <see cref="IObjectSerializer"/> that uses System.Text.Json.
|
||||
/// Based on <see cref="Microsoft.Toolkit.Helpers.IObjectSerializer"/>.
|
||||
/// </summary>
|
||||
internal class SystemTextJsonSerializer2 : IObjectSerializer
|
||||
{
|
||||
public T Deserialize<T>(string value) => JsonSerializer.Deserialize<T>(value);
|
||||
|
||||
public string Serialize<T>(T value) => JsonSerializer.Serialize(value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,181 @@
|
|||
// Licensed to the .NET Foundation under one or more agreements.
|
||||
// The .NET Foundation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using Microsoft.Toolkit.Uwp.Helpers;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace UnitTests.Helpers
|
||||
{
|
||||
[TestClass]
|
||||
public class Test_ApplicationDataStorageHelper
|
||||
{
|
||||
private readonly ApplicationDataStorageHelper _settingsStorage_System = ApplicationDataStorageHelper.GetCurrent();
|
||||
private readonly ApplicationDataStorageHelper _settingsStorage_JsonCompat = ApplicationDataStorageHelper.GetCurrent(new JsonObjectSerializer2());
|
||||
private readonly ApplicationDataStorageHelper _settingsStorage_JsonNew = ApplicationDataStorageHelper.GetCurrent(new SystemTextJsonSerializer2());
|
||||
|
||||
/// <summary>
|
||||
/// Checks that we're running 10.0.3 version of Newtonsoft.Json package which we used in 6.1.1.
|
||||
/// </summary>
|
||||
[TestCategory("Helpers")]
|
||||
[TestMethod]
|
||||
public void Test_StorageHelper_CheckNewtonsoftVersion()
|
||||
{
|
||||
var version = typeof(Newtonsoft.Json.JsonSerializer).Assembly.GetName().Version;
|
||||
Assert.AreEqual(10, version.Major);
|
||||
Assert.AreEqual(0, version.Minor);
|
||||
Assert.AreEqual(0, version.Revision); // Apparently the file revision was not updated for the updated package
|
||||
}
|
||||
|
||||
[TestCategory("Helpers")]
|
||||
[TestMethod]
|
||||
public void Test_StorageHelper_LegacyIntTest()
|
||||
{
|
||||
string key = "LifeUniverseAndEverything";
|
||||
|
||||
int input = 42;
|
||||
|
||||
// Use our previous Json layer to store value
|
||||
_settingsStorage_JsonCompat.Save(key, input);
|
||||
|
||||
// But try and read from our new system to see if it works
|
||||
int output = _settingsStorage_System.Read(key, 0);
|
||||
|
||||
Assert.AreEqual(input, output);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If we try and deserialize a complex type with the <see cref="Microsoft.Toolkit.Helpers.SystemSerializer"/>, we do a check ourselves and will throw our own exception.
|
||||
/// </summary>
|
||||
[TestCategory("Helpers")]
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(NotSupportedException))]
|
||||
public void Test_StorageHelper_LegacyDateTestFailure()
|
||||
{
|
||||
string key = "ChristmasDay";
|
||||
|
||||
DateTime input = new DateTime(2017, 12, 25);
|
||||
|
||||
_settingsStorage_JsonCompat.Save(key, input);
|
||||
|
||||
// now read it as int to valid that the change works
|
||||
_ = _settingsStorage_System.Read(key, DateTime.Today);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Microsoft.Toolkit.Helpers.SystemSerializer"/> doesn't support complex types, since it just passes through directly.
|
||||
/// We'll get the argument exception from the <see cref="Windows.Storage.ApplicationDataContainer"/> API.
|
||||
/// </summary>
|
||||
[TestCategory("Helpers")]
|
||||
[TestMethod]
|
||||
[ExpectedException(typeof(NotSupportedException))]
|
||||
public void Test_StorageHelper_DateTestFailure()
|
||||
{
|
||||
string key = "Today";
|
||||
|
||||
_settingsStorage_System.Save(key, DateTime.Today);
|
||||
_settingsStorage_System.TryRead<DateTime>(key, out _);
|
||||
}
|
||||
|
||||
[TestCategory("Helpers")]
|
||||
[TestMethod]
|
||||
public void Test_StorageHelper_LegacyInternalClassTest()
|
||||
{
|
||||
string key = "Contact";
|
||||
|
||||
UI.Person input = new UI.Person() { Name = "Joe Bloggs", Age = 42 };
|
||||
|
||||
// simulate previous version by generating json and manually inserting it as string
|
||||
_settingsStorage_JsonCompat.Save(key, input);
|
||||
|
||||
// now read it as int to valid that the change works
|
||||
UI.Person output = _settingsStorage_JsonCompat.Read<UI.Person>(key, null);
|
||||
|
||||
Assert.IsNotNull(output);
|
||||
Assert.AreEqual(input.Name, output.Name);
|
||||
Assert.AreEqual(input.Age, output.Age);
|
||||
}
|
||||
|
||||
[TestCategory("Helpers")]
|
||||
[TestMethod]
|
||||
public void Test_StorageHelper_LegacyPublicClassTest()
|
||||
{
|
||||
string key = "Contact";
|
||||
|
||||
// Here's we're serializing a different class which has the same properties as our other class below.
|
||||
UI.Person input = new UI.Person() { Name = "Joe Bloggs", Age = 42 };
|
||||
|
||||
// simulate previous version by generating json and manually inserting it as string
|
||||
_settingsStorage_JsonCompat.Save(key, input);
|
||||
|
||||
// now read it as int to valid that the change works
|
||||
Person output = _settingsStorage_JsonCompat.Read<Person>(key, null);
|
||||
|
||||
Assert.IsNotNull(output);
|
||||
Assert.AreEqual(input.Name, output.Name);
|
||||
Assert.AreEqual(input.Age, output.Age);
|
||||
}
|
||||
|
||||
[TestCategory("Helpers")]
|
||||
[TestMethod]
|
||||
public void Test_StorageHelper_IntTest()
|
||||
{
|
||||
string key = "NewLifeUniverseAndEverything";
|
||||
|
||||
int input = 42;
|
||||
|
||||
_settingsStorage_System.Save<int>(key, input);
|
||||
|
||||
// now read it as int to valid that the change works
|
||||
int output = _settingsStorage_System.Read<int>(key, 0);
|
||||
|
||||
Assert.AreEqual(input, output);
|
||||
}
|
||||
|
||||
[TestCategory("Helpers")]
|
||||
[TestMethod]
|
||||
public void Test_StorageHelper_NewDateTest()
|
||||
{
|
||||
string key = "NewChristmasDay";
|
||||
|
||||
DateTime input = new DateTime(2017, 12, 25);
|
||||
|
||||
_settingsStorage_JsonNew.Save(key, input);
|
||||
|
||||
// now read it as int to valid that the change works
|
||||
DateTime output = _settingsStorage_JsonNew.Read(key, DateTime.Today);
|
||||
|
||||
Assert.AreEqual(input, output);
|
||||
}
|
||||
|
||||
[TestCategory("Helpers")]
|
||||
[TestMethod]
|
||||
public void Test_StorageHelper_NewPersonTest()
|
||||
{
|
||||
string key = "Contact";
|
||||
|
||||
Person input = new Person() { Name = "Joe Bloggs", Age = 42 };
|
||||
|
||||
_settingsStorage_JsonNew.Save(key, input);
|
||||
|
||||
// now read it as int to valid that the change works
|
||||
Person output = _settingsStorage_JsonNew.Read<Person>(key, null);
|
||||
|
||||
Assert.IsNotNull(output);
|
||||
Assert.AreEqual(input.Name, output.Name);
|
||||
Assert.AreEqual(input.Age, output.Age);
|
||||
}
|
||||
|
||||
public class Person
|
||||
{
|
||||
public string Name { get; set; }
|
||||
|
||||
public int Age { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,7 +6,7 @@ using System;
|
|||
using CommunityToolkit.WinUI.Helpers;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Newtonsoft.Json;
|
||||
using UnitTests.UWP.Helpers;
|
||||
using UnitTests.Helpers;
|
||||
using Windows.Storage;
|
||||
|
||||
namespace UnitTests.Helpers
|
||||
|
@ -14,10 +14,12 @@ namespace UnitTests.Helpers
|
|||
[TestClass]
|
||||
public class Test_StorageHelper
|
||||
{
|
||||
private LocalObjectStorageHelper _localStorageHelperSystem = new LocalObjectStorageHelper(new SystemSerializer());
|
||||
private LocalObjectStorageHelper _localStorageHelperJsonCompat = new LocalObjectStorageHelper(new JsonObjectSerializer());
|
||||
|
||||
private LocalObjectStorageHelper _localStorageHelperJsonNew = new LocalObjectStorageHelper(new SystemTextJsonSerializer());
|
||||
[Obsolete]
|
||||
private readonly LocalObjectStorageHelper _localStorageHelperSystem = new LocalObjectStorageHelper(new SystemSerializer());
|
||||
[Obsolete]
|
||||
private readonly LocalObjectStorageHelper _localStorageHelperJsonCompat = new LocalObjectStorageHelper(new JsonObjectSerializer());
|
||||
[Obsolete]
|
||||
private readonly LocalObjectStorageHelper _localStorageHelperJsonNew = new LocalObjectStorageHelper(new SystemTextJsonSerializer());
|
||||
|
||||
/// <summary>
|
||||
/// Checks that we're running 10.0.3 version of Newtonsoft.Json package which we used in 6.1.1.
|
||||
|
@ -34,6 +36,7 @@ namespace UnitTests.Helpers
|
|||
|
||||
[TestCategory("Helpers")]
|
||||
[TestMethod]
|
||||
[Obsolete]
|
||||
public void Test_StorageHelper_LegacyIntTest()
|
||||
{
|
||||
string key = "LifeUniverseAndEverything";
|
||||
|
@ -54,6 +57,7 @@ namespace UnitTests.Helpers
|
|||
/// </summary>
|
||||
[TestCategory("Helpers")]
|
||||
[TestMethod]
|
||||
[Obsolete]
|
||||
[ExpectedException(typeof(NotSupportedException))]
|
||||
public void Test_StorageHelper_LegacyDateTestFailure()
|
||||
{
|
||||
|
@ -73,6 +77,7 @@ namespace UnitTests.Helpers
|
|||
/// </summary>
|
||||
[TestCategory("Helpers")]
|
||||
[TestMethod]
|
||||
[Obsolete]
|
||||
public void Test_StorageHelper_DateTestFailure()
|
||||
{
|
||||
Exception expectedException = null;
|
||||
|
@ -93,6 +98,7 @@ namespace UnitTests.Helpers
|
|||
|
||||
[TestCategory("Helpers")]
|
||||
[TestMethod]
|
||||
[Obsolete]
|
||||
public void Test_StorageHelper_LegacyInternalClassTest()
|
||||
{
|
||||
string key = "Contact";
|
||||
|
@ -112,6 +118,7 @@ namespace UnitTests.Helpers
|
|||
|
||||
[TestCategory("Helpers")]
|
||||
[TestMethod]
|
||||
[Obsolete]
|
||||
public void Test_StorageHelper_LegacyPublicClassTest()
|
||||
{
|
||||
string key = "Contact";
|
||||
|
@ -132,6 +139,7 @@ namespace UnitTests.Helpers
|
|||
|
||||
[TestCategory("Helpers")]
|
||||
[TestMethod]
|
||||
[Obsolete]
|
||||
public void Test_StorageHelper_IntTest()
|
||||
{
|
||||
string key = "NewLifeUniverseAndEverything";
|
||||
|
@ -148,6 +156,7 @@ namespace UnitTests.Helpers
|
|||
|
||||
[TestCategory("Helpers")]
|
||||
[TestMethod]
|
||||
[Obsolete]
|
||||
public void Test_StorageHelper_NewDateTest()
|
||||
{
|
||||
string key = "NewChristmasDay";
|
||||
|
@ -164,6 +173,7 @@ namespace UnitTests.Helpers
|
|||
|
||||
[TestCategory("Helpers")]
|
||||
[TestMethod]
|
||||
[Obsolete]
|
||||
public void Test_StorageHelper_NewPersonTest()
|
||||
{
|
||||
string key = "Contact";
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using Microsoft.Toolkit.Helpers;
|
||||
using Microsoft.Toolkit.Uwp.Helpers;
|
||||
using Microsoft.VisualStudio.TestTools.UnitTesting;
|
||||
using Windows.ApplicationModel;
|
||||
|
@ -57,10 +58,10 @@ namespace UnitTests.Helpers
|
|||
// Simulate a first app startup
|
||||
_ = (SystemInformation)Activator.CreateInstance(typeof(SystemInformation), nonPublic: true);
|
||||
|
||||
LocalObjectStorageHelper localObjectStorageHelper = new(new SystemSerializer());
|
||||
var settingsStorage = ApplicationDataStorageHelper.GetCurrent();
|
||||
PackageVersion previousVersion = new() { Build = 42, Major = 1111, Minor = 2222, Revision = 12345 };
|
||||
|
||||
localObjectStorageHelper.Save("currentVersion", previousVersion.ToFormattedString());
|
||||
settingsStorage.Save("currentVersion", previousVersion.ToFormattedString());
|
||||
|
||||
var systemInformation = (SystemInformation)Activator.CreateInstance(typeof(SystemInformation), nonPublic: true);
|
||||
var currentAppVersion = Package.Current.Id.Version;
|
||||
|
|
|
@ -79,10 +79,13 @@
|
|||
<Compile Include="Geometry\Test_Utils.cs" />
|
||||
<Compile Include="GlobalSuppressions.cs" />
|
||||
<Compile Include="Helpers\JsonObjectSerializer.cs" />
|
||||
<Compile Include="Helpers\JsonObjectSerializer2.cs" />
|
||||
<Compile Include="Helpers\SystemTextJsonSerializer.cs" />
|
||||
<Compile Include="Helpers\SystemTextJsonSerializer2.cs" />
|
||||
<Compile Include="Helpers\TestCollectionCapableDeepLinkParser.cs" />
|
||||
<Compile Include="Helpers\TestDeepLinkParser.cs" />
|
||||
<Compile Include="Extensions\Test_DispatcherQueueExtensions.cs" />
|
||||
<Compile Include="Helpers\Test_ApplicationDataStorageHelper.cs" />
|
||||
<Compile Include="Helpers\Test_DispatcherHelper.cs" />
|
||||
<Compile Include="Helpers\Test_AdvancedCollectionView.cs" />
|
||||
<Compile Include="Helpers\Test_BackgroundTaskHelper.cs" />
|
||||
|
|
|
@ -56,12 +56,12 @@ jobs:
|
|||
version: 5.0.302
|
||||
performMultiLevelLookup: true
|
||||
|
||||
- powershell: .\build\build.ps1 --target=Build
|
||||
- powershell: .\build\build.ps1 -Target Build
|
||||
displayName: Build
|
||||
|
||||
### Unit Tests ###
|
||||
|
||||
# - powershell: .\build\build.ps1 --target=Test
|
||||
# - powershell: .\build\build.ps1 -Target Test
|
||||
# displayName: Test
|
||||
|
||||
- task: PublishTestResults@2
|
||||
|
@ -73,7 +73,7 @@ jobs:
|
|||
|
||||
### UI Integration Tests ###
|
||||
|
||||
- powershell: .\build\build.ps1 --target=UITest
|
||||
- powershell: .\build\build.ps1 -Target UITest
|
||||
displayName: UI Integration Tests
|
||||
|
||||
- task: PublishPipelineArtifact@1
|
||||
|
@ -92,7 +92,7 @@ jobs:
|
|||
|
||||
### Package ###
|
||||
|
||||
- powershell: .\build\build.ps1 --target=Package
|
||||
- powershell: .\build\build.ps1 -Target Package
|
||||
displayName: Package
|
||||
|
||||
- task: PowerShell@2
|
||||
|
@ -134,7 +134,7 @@ jobs:
|
|||
# - script: nbgv cloud
|
||||
# displayName: Set Version
|
||||
#
|
||||
# - powershell: .\build\build.ps1 --target=SmokeTest
|
||||
# - powershell: .\build\build.ps1 -Target SmokeTest
|
||||
# displayName: SmokeTest
|
||||
#
|
||||
# - task: CopyFiles@2
|
||||
|
@ -150,12 +150,5 @@ jobs:
|
|||
# artifactType: container
|
||||
# artifactName: SmokeTestBundles
|
||||
|
||||
# - task: PublishBuildArtifacts@1
|
||||
# displayName: Publish Smoke Test Artifacts
|
||||
# inputs:
|
||||
# pathToPublish: $(build.artifactstagingdirectory)\SmokeTestBundles
|
||||
# artifactType: container
|
||||
# artifactName: SmokeTestBundles
|
||||
#
|
||||
# - powershell: .\SmokeTests\SmokeTestAnalysis.ps1
|
||||
# displayName: Analyze Package Sizes
|
||||
|
|
|
@ -5,8 +5,7 @@ $ErrorActionPreference = 'Stop'
|
|||
# Unique set of Windows SDK versions referenced in files
|
||||
$versions = New-Object System.Collections.Generic.HashSet[System.String]
|
||||
|
||||
function Get-Nodes
|
||||
{
|
||||
function Get-Nodes {
|
||||
param(
|
||||
[parameter(ValueFromPipeline = $true)]
|
||||
[xml] $xml,
|
||||
|
@ -24,8 +23,7 @@ function Get-Nodes
|
|||
return $r
|
||||
}
|
||||
|
||||
function Get-NodeValue
|
||||
{
|
||||
function Get-NodeValue {
|
||||
param(
|
||||
[parameter(ValueFromPipeline = $true)]
|
||||
[xml] $xml,
|
||||
|
@ -42,8 +40,7 @@ function Get-NodeValue
|
|||
return [string]""
|
||||
}
|
||||
|
||||
function Get-SdkVersion
|
||||
{
|
||||
function Get-SdkVersion {
|
||||
param(
|
||||
[Parameter(ValueFromPipeline = $true)] $file)
|
||||
|
||||
|
@ -67,8 +64,7 @@ function Get-SdkVersion
|
|||
$versions.Add("10.0." + $version + ".0") | Out-Null
|
||||
}
|
||||
|
||||
function Test-RegistryPathAndValue
|
||||
{
|
||||
function Test-RegistryPathAndValue {
|
||||
param (
|
||||
[parameter(Mandatory = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
|
@ -77,16 +73,13 @@ function Test-RegistryPathAndValue
|
|||
[ValidateNotNullOrEmpty()]
|
||||
[string] $value)
|
||||
|
||||
try
|
||||
{
|
||||
if (Test-Path $path)
|
||||
{
|
||||
try {
|
||||
if (Test-Path $path) {
|
||||
Get-ItemProperty -Path $path | Select-Object -ExpandProperty $value -ErrorAction Stop | Out-Null
|
||||
return $true
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
catch {
|
||||
}
|
||||
|
||||
return $false
|
||||
|
@ -101,24 +94,18 @@ function Test-InstallWindowsSdk([string] $WindowsSDKVersion) {
|
|||
|
||||
$WindowsSDKInstalledRegPath = "$WindowsSDKRegPath\$WindowsSDKVersion\Installed Options"
|
||||
|
||||
if (Test-RegistryPathAndValue -Path $WindowsSDKRegPath -Value $WindowsSDKRegRootKey)
|
||||
{
|
||||
if (Test-RegistryPathAndValue -Path $WindowsSDKRegPath -Value $WindowsSDKRegRootKey) {
|
||||
# A Windows SDK is installed
|
||||
# Is an SDK of our version installed with the options we need?
|
||||
if (Test-RegistryPathAndValue -Path $WindowsSDKInstalledRegPath -Value "$WindowsSDKOptions")
|
||||
{
|
||||
if (Test-RegistryPathAndValue -Path $WindowsSDKInstalledRegPath -Value "$WindowsSDKOptions") {
|
||||
# It appears we have what we need. Double check the disk
|
||||
$sdkRoot = Get-ItemProperty -Path $WindowsSDKRegPath | Select-Object -ExpandProperty $WindowsSDKRegRootKey
|
||||
if ($sdkRoot)
|
||||
{
|
||||
if (Test-Path $sdkRoot)
|
||||
{
|
||||
if ($sdkRoot) {
|
||||
if (Test-Path $sdkRoot) {
|
||||
$refPath = Join-Path $sdkRoot "References\$WindowsSDKVersion"
|
||||
if (Test-Path $refPath)
|
||||
{
|
||||
if (Test-Path $refPath) {
|
||||
$umdPath = Join-Path $sdkRoot "UnionMetadata\$WindowsSDKVersion"
|
||||
if (Test-Path $umdPath)
|
||||
{
|
||||
if (Test-Path $umdPath) {
|
||||
# Pretty sure we have what we need
|
||||
$retval = $false
|
||||
}
|
||||
|
@ -160,6 +147,7 @@ foreach($version in $versions) {
|
|||
Write-Host
|
||||
if ($anyInstallRequired) {
|
||||
throw "At least one Windows SDK is missing from this machine"
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
Write-Host "All referenced Windows SDKs are installed!"
|
||||
}
|
|
@ -1,6 +1,10 @@
|
|||
mkdir c:\winsdktemp
|
||||
|
||||
$client = new-object System.Net.WebClient
|
||||
$client.DownloadFile("https://go.microsoft.com/fwlink/p/?linkid=870807","c:\winsdktemp\winsdksetup.exe")
|
||||
$WinSdkTempDir = "C:\WinSdkTemp\"
|
||||
$WinSdkSetupExe = "C:\WinSdkTemp\" + "WinSdkSetup.exe"
|
||||
|
||||
Start-Process -Wait "c:\winsdktemp\winsdksetup.exe" "/features OptionId.UWPCpp /q"
|
||||
mkdir $WinSdkTempDir
|
||||
|
||||
$client = [System.Net.WebClient]::new()
|
||||
$client.DownloadFile("https://go.microsoft.com/fwlink/p/?linkid=870807", $WinSdkSetupExe)
|
||||
|
||||
Start-Process -Wait $WinSdkSetupExe "/features OptionId.UWPCpp /q"
|
|
@ -14,8 +14,7 @@ $WindowsSDKInstalledRegPath = "$WindowsSDKRegPath\$WindowsSDKVersion\Installed O
|
|||
$StrongNameRegPath = "HKLM:\SOFTWARE\Microsoft\StrongName\Verification"
|
||||
$PublicKeyTokens = @("31bf3856ad364e35")
|
||||
|
||||
function Download-File
|
||||
{
|
||||
function Download-File {
|
||||
param ([string] $outDir,
|
||||
[string] $downloadUrl,
|
||||
[string] $downloadName)
|
||||
|
@ -26,21 +25,17 @@ function Download-File
|
|||
|
||||
Write-Host -NoNewline "Downloading $downloadName..."
|
||||
|
||||
try
|
||||
{
|
||||
try {
|
||||
$webclient = new-object System.Net.WebClient
|
||||
$webclient.DownloadFile($downloadUrl, $downloadPath)
|
||||
}
|
||||
catch [System.Net.WebException]
|
||||
{
|
||||
catch [System.Net.WebException] {
|
||||
Write-Host
|
||||
Write-Warning "Failed to fetch updated file from $downloadUrl"
|
||||
if (!(Test-Path $downloadDest))
|
||||
{
|
||||
if (!(Test-Path $downloadDest)) {
|
||||
throw "$downloadName was not found at $downloadDest"
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
Write-Warning "$downloadName may be out of date"
|
||||
}
|
||||
}
|
||||
|
@ -50,8 +45,7 @@ function Download-File
|
|||
$downloadDestTemp = $downloadPath;
|
||||
|
||||
# Delete and rename to final dest
|
||||
if (Test-Path -PathType Container $downloadDest)
|
||||
{
|
||||
if (Test-Path -PathType Container $downloadDest) {
|
||||
[System.IO.Directory]::Delete($downloadDest, $true)
|
||||
}
|
||||
|
||||
|
@ -61,20 +55,16 @@ function Download-File
|
|||
return $downloadDest
|
||||
}
|
||||
|
||||
function Get-ISODriveLetter
|
||||
{
|
||||
function Get-ISODriveLetter {
|
||||
param ([string] $isoPath)
|
||||
|
||||
$diskImage = Get-DiskImage -ImagePath $isoPath
|
||||
if ($diskImage)
|
||||
{
|
||||
if ($diskImage) {
|
||||
$volume = Get-Volume -DiskImage $diskImage
|
||||
|
||||
if ($volume)
|
||||
{
|
||||
if ($volume) {
|
||||
$driveLetter = $volume.DriveLetter
|
||||
if ($driveLetter)
|
||||
{
|
||||
if ($driveLetter) {
|
||||
$driveLetter += ":"
|
||||
return $driveLetter
|
||||
}
|
||||
|
@ -84,15 +74,13 @@ function Get-ISODriveLetter
|
|||
return $null
|
||||
}
|
||||
|
||||
function Mount-ISO
|
||||
{
|
||||
function Mount-ISO {
|
||||
param ([string] $isoPath)
|
||||
|
||||
# Check if image is already mounted
|
||||
$isoDrive = Get-ISODriveLetter $isoPath
|
||||
|
||||
if (!$isoDrive)
|
||||
{
|
||||
if (!$isoDrive) {
|
||||
Mount-DiskImage -ImagePath $isoPath -StorageType ISO | Out-Null
|
||||
}
|
||||
|
||||
|
@ -100,39 +88,33 @@ function Mount-ISO
|
|||
Write-Verbose "$isoPath mounted to ${isoDrive}:"
|
||||
}
|
||||
|
||||
function Dismount-ISO
|
||||
{
|
||||
function Dismount-ISO {
|
||||
param ([string] $isoPath)
|
||||
|
||||
$isoDrive = (Get-DiskImage -ImagePath $isoPath | Get-Volume).DriveLetter
|
||||
|
||||
if ($isoDrive)
|
||||
{
|
||||
if ($isoDrive) {
|
||||
Write-Verbose "$isoPath dismounted"
|
||||
Dismount-DiskImage -ImagePath $isoPath | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
function Disable-StrongName
|
||||
{
|
||||
function Disable-StrongName {
|
||||
param ([string] $publicKeyToken = "*")
|
||||
|
||||
reg ADD "HKLM\SOFTWARE\Microsoft\StrongName\Verification\*,$publicKeyToken" /f | Out-Null
|
||||
if ($env:PROCESSOR_ARCHITECTURE -eq "AMD64")
|
||||
{
|
||||
if ($env:PROCESSOR_ARCHITECTURE -eq "AMD64") {
|
||||
reg ADD "HKLM\SOFTWARE\Wow6432Node\Microsoft\StrongName\Verification\*,$publicKeyToken" /f | Out-Null
|
||||
}
|
||||
}
|
||||
|
||||
function Test-Admin
|
||||
{
|
||||
function Test-Admin {
|
||||
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
|
||||
$principal = New-Object Security.Principal.WindowsPrincipal $identity
|
||||
$principal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
|
||||
}
|
||||
|
||||
function Test-RegistryPathAndValue
|
||||
{
|
||||
function Test-RegistryPathAndValue {
|
||||
param (
|
||||
[parameter(Mandatory = $true)]
|
||||
[ValidateNotNullOrEmpty()]
|
||||
|
@ -141,43 +123,33 @@ function Test-RegistryPathAndValue
|
|||
[ValidateNotNullOrEmpty()]
|
||||
[string] $value)
|
||||
|
||||
try
|
||||
{
|
||||
if (Test-Path $path)
|
||||
{
|
||||
try {
|
||||
if (Test-Path $path) {
|
||||
Get-ItemProperty -Path $path | Select-Object -ExpandProperty $value -ErrorAction Stop | Out-Null
|
||||
return $true
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
catch {
|
||||
}
|
||||
|
||||
return $false
|
||||
}
|
||||
|
||||
function Test-InstallWindowsSDK
|
||||
{
|
||||
function Test-InstallWindowsSDK {
|
||||
$retval = $true
|
||||
|
||||
if (Test-RegistryPathAndValue -Path $WindowsSDKRegPath -Value $WindowsSDKRegRootKey)
|
||||
{
|
||||
if (Test-RegistryPathAndValue -Path $WindowsSDKRegPath -Value $WindowsSDKRegRootKey) {
|
||||
# A Windows SDK is installed
|
||||
# Is an SDK of our version installed with the options we need?
|
||||
if (Test-RegistryPathAndValue -Path $WindowsSDKInstalledRegPath -Value "$WindowsSDKOptions")
|
||||
{
|
||||
if (Test-RegistryPathAndValue -Path $WindowsSDKInstalledRegPath -Value "$WindowsSDKOptions") {
|
||||
# It appears we have what we need. Double check the disk
|
||||
$sdkRoot = Get-ItemProperty -Path $WindowsSDKRegPath | Select-Object -ExpandProperty $WindowsSDKRegRootKey
|
||||
if ($sdkRoot)
|
||||
{
|
||||
if (Test-Path $sdkRoot)
|
||||
{
|
||||
if ($sdkRoot) {
|
||||
if (Test-Path $sdkRoot) {
|
||||
$refPath = Join-Path $sdkRoot "References\$WindowsSDKVersion"
|
||||
if (Test-Path $refPath)
|
||||
{
|
||||
if (Test-Path $refPath) {
|
||||
$umdPath = Join-Path $sdkRoot "UnionMetadata\$WindowsSDKVersion"
|
||||
if (Test-Path $umdPath)
|
||||
{
|
||||
if (Test-Path $umdPath) {
|
||||
# Pretty sure we have what we need
|
||||
$retval = $false
|
||||
}
|
||||
|
@ -190,13 +162,10 @@ function Test-InstallWindowsSDK
|
|||
return $retval
|
||||
}
|
||||
|
||||
function Test-InstallStrongNameHijack
|
||||
{
|
||||
foreach($publicKeyToken in $PublicKeyTokens)
|
||||
{
|
||||
function Test-InstallStrongNameHijack {
|
||||
foreach ($publicKeyToken in $PublicKeyTokens) {
|
||||
$key = "$StrongNameRegPath\*,$publicKeyToken"
|
||||
if (!(Test-Path $key))
|
||||
{
|
||||
if (!(Test-Path $key)) {
|
||||
return $true
|
||||
}
|
||||
}
|
||||
|
@ -206,51 +175,42 @@ function Test-InstallStrongNameHijack
|
|||
|
||||
Write-Host -NoNewline "Checking for installed Windows SDK $WindowsSDKVersion..."
|
||||
$InstallWindowsSDK = Test-InstallWindowsSDK
|
||||
if ($InstallWindowsSDK)
|
||||
{
|
||||
if ($InstallWindowsSDK) {
|
||||
Write-Host "Installation required"
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
Write-Host "INSTALLED"
|
||||
}
|
||||
|
||||
$StrongNameHijack = Test-InstallStrongNameHijack
|
||||
Write-Host -NoNewline "Checking if StrongName bypass required..."
|
||||
|
||||
if ($StrongNameHijack)
|
||||
{
|
||||
if ($StrongNameHijack) {
|
||||
Write-Host "REQUIRED"
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
Write-Host "Done"
|
||||
}
|
||||
|
||||
if ($StrongNameHijack -or $InstallWindowsSDK)
|
||||
{
|
||||
if (!(Test-Admin))
|
||||
{
|
||||
if ($StrongNameHijack -or $InstallWindowsSDK) {
|
||||
if (!(Test-Admin)) {
|
||||
Write-Host
|
||||
throw "ERROR: Elevation required"
|
||||
}
|
||||
}
|
||||
|
||||
if ($InstallWindowsSDK)
|
||||
{
|
||||
if ($InstallWindowsSDK) {
|
||||
# Static(ish) link for Windows SDK
|
||||
# Note: there is a delay from Windows SDK announcements to availability via the static link
|
||||
$uri = "https://software-download.microsoft.com/download/sg/Windows_InsiderPreview_SDK_en-us_$($buildNumber)_1.iso";
|
||||
|
||||
if ($env:TEMP -eq $null)
|
||||
{
|
||||
if ($null -eq $env:TEMP) {
|
||||
$env:TEMP = Join-Path $env:SystemDrive 'temp'
|
||||
}
|
||||
|
||||
$winsdkTempDir = Join-Path $env:TEMP "WindowsSDK"
|
||||
|
||||
if (![System.IO.Directory]::Exists($winsdkTempDir))
|
||||
{
|
||||
if (![System.IO.Directory]::Exists($winsdkTempDir)) {
|
||||
[void][System.IO.Directory]::CreateDirectory($winsdkTempDir)
|
||||
}
|
||||
|
||||
|
@ -260,41 +220,35 @@ if ($InstallWindowsSDK)
|
|||
$downloadFile = Download-File $winsdkTempDir $uri $file
|
||||
|
||||
# TODO Check if zip, exe, iso, etc.
|
||||
try
|
||||
{
|
||||
try {
|
||||
Write-Host -NoNewline "Mounting ISO $file..."
|
||||
Mount-ISO $downloadFile
|
||||
Write-Host "Done"
|
||||
|
||||
$isoDrive = Get-ISODriveLetter $downloadFile
|
||||
|
||||
if (Test-Path $isoDrive)
|
||||
{
|
||||
if (Test-Path $isoDrive) {
|
||||
Write-Host -NoNewLine "Installing WinSDK..."
|
||||
|
||||
$setupPath = Join-Path "$isoDrive" "WinSDKSetup.exe"
|
||||
Start-Process -Wait $setupPath "/features $WindowsSDKOptions /q"
|
||||
Write-Host "Done"
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
throw "Could not find mounted ISO at ${isoDrive}"
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
finally {
|
||||
Write-Host -NoNewline "Dismounting ISO $file..."
|
||||
# Dismount-ISO $downloadFile
|
||||
Write-Host "Done"
|
||||
}
|
||||
}
|
||||
|
||||
if ($StrongNameHijack)
|
||||
{
|
||||
if ($StrongNameHijack) {
|
||||
Write-Host -NoNewline "Disabling StrongName for Windows SDK..."
|
||||
|
||||
foreach($key in $PublicKeyTokens)
|
||||
{
|
||||
foreach ($key in $PublicKeyTokens) {
|
||||
Disable-StrongName $key
|
||||
}
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ dotnet tool install --tool-path . SignClient
|
|||
|
||||
$appSettings = "$currentDirectory\SignClientSettings.json"
|
||||
|
||||
$nupkgs = gci $Env:ArtifactDirectory\*.nupkg -recurse | Select -ExpandProperty FullName
|
||||
$nupkgs = Get-ChildItem $Env:ArtifactDirectory\*.nupkg -recurse | Select-Object -ExpandProperty FullName
|
||||
|
||||
foreach ($nupkg in $nupkgs) {
|
||||
Write-Host "Submitting $nupkg for signing"
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
@ECHO OFF
|
||||
PowerShell.exe -file "%~dp0build.ps1" --target=StyleXaml
|
||||
PowerShell.exe -file "%~dp0build.ps1" -Target StyleXaml
|
||||
PAUSE
|
|
@ -1,3 +1,3 @@
|
|||
@ECHO OFF
|
||||
PowerShell.exe -file "%~dp0build.ps1" --target=UpdateHeaders
|
||||
PowerShell.exe -file "%~dp0build.ps1" -Target UpdateHeaders
|
||||
PAUSE
|
|
@ -1,10 +1,10 @@
|
|||
#module nuget:?package=Cake.LongPath.Module&version=1.0.1
|
||||
|
||||
#addin nuget:?package=Cake.FileHelpers&version=4.0.1
|
||||
#addin nuget:?package=Cake.Powershell&version=1.0.0
|
||||
#addin nuget:?package=Cake.GitVersioning&version=3.4.190
|
||||
#addin nuget:?package=Cake.Powershell&version=1.0.1
|
||||
#addin nuget:?package=Cake.GitVersioning&version=3.4.220
|
||||
|
||||
#tool nuget:?package=MSTest.TestAdapter&version=2.1.0
|
||||
#tool nuget:?package=MSTest.TestAdapter&version=2.2.5
|
||||
#tool nuget:?package=vswhere&version=2.8.4
|
||||
|
||||
using System;
|
||||
|
@ -94,7 +94,7 @@ void VerifyHeaders(bool Replace)
|
|||
|
||||
if(!Replace && hasMissing)
|
||||
{
|
||||
throw new Exception("Please run UpdateHeaders.bat or '.\\build.ps1 --target=UpdateHeaders' and commit the changes.");
|
||||
throw new Exception("Please run UpdateHeaders.bat or '.\\build.ps1 -Target UpdateHeaders' and commit the changes.");
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -196,7 +196,8 @@ Task("InheritDoc")
|
|||
.Does(() =>
|
||||
{
|
||||
Information("\nDownloading InheritDoc...");
|
||||
var installSettings = new NuGetInstallSettings {
|
||||
var installSettings = new NuGetInstallSettings
|
||||
{
|
||||
ExcludeVersion = true,
|
||||
Version = inheritDocVersion,
|
||||
OutputDirectory = toolsDir
|
||||
|
@ -230,7 +231,8 @@ Task("Package")
|
|||
.Does(() =>
|
||||
{
|
||||
// Invoke the pack target in the end
|
||||
var buildSettings = new MSBuildSettings {
|
||||
var buildSettings = new MSBuildSettings
|
||||
{
|
||||
MaxCpuCount = 0
|
||||
}
|
||||
.SetConfiguration("Release")
|
||||
|
@ -335,7 +337,6 @@ Task("MSTestUITest")
|
|||
DotNetCoreTest(file.FullPath, testSettings);
|
||||
});
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// TASK TARGETS
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
@ -358,7 +359,8 @@ Task("StyleXaml")
|
|||
.Does(() =>
|
||||
{
|
||||
Information("\nDownloading XamlStyler...");
|
||||
var installSettings = new NuGetInstallSettings {
|
||||
var installSettings = new NuGetInstallSettings
|
||||
{
|
||||
ExcludeVersion = true,
|
||||
OutputDirectory = toolsDir
|
||||
};
|
||||
|
@ -376,8 +378,6 @@ Task("StyleXaml")
|
|||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// EXECUTION
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
|
|
@ -10,6 +10,7 @@ This is a Powershell script to bootstrap a Cake build.
|
|||
.DESCRIPTION
|
||||
This Powershell script will download NuGet if missing, restore NuGet tools (including Cake)
|
||||
and execute your Cake build script with the parameters you provide.
|
||||
|
||||
.PARAMETER Script
|
||||
The build script to execute.
|
||||
.PARAMETER Target
|
||||
|
@ -85,10 +86,15 @@ function MD5HashFile([string] $filePath)
|
|||
}
|
||||
finally
|
||||
{
|
||||
if ($file -ne $null)
|
||||
if ($null -ne $file)
|
||||
{
|
||||
$file.Dispose()
|
||||
}
|
||||
|
||||
if ($null -ne $md5)
|
||||
{
|
||||
$md5.Dispose()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,7 +153,7 @@ if (!(Test-Path $NUGET_EXE)) {
|
|||
Write-Verbose -Message "Trying to find nuget.exe in PATH..."
|
||||
$existingPaths = $Env:Path -Split ';' | Where-Object { (![string]::IsNullOrEmpty($_)) -and (Test-Path $_ -PathType Container) }
|
||||
$NUGET_EXE_IN_PATH = Get-ChildItem -Path $existingPaths -Filter "nuget.exe" | Select -First 1
|
||||
if ($NUGET_EXE_IN_PATH -ne $null -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) {
|
||||
if ($null -ne $NUGET_EXE_IN_PATH -and (Test-Path $NUGET_EXE_IN_PATH.FullName)) {
|
||||
Write-Verbose -Message "Found in PATH at $($NUGET_EXE_IN_PATH.FullName)."
|
||||
$NUGET_EXE = $NUGET_EXE_IN_PATH.FullName
|
||||
}
|
||||
|
@ -165,7 +171,7 @@ if (!(Test-Path $NUGET_EXE)) {
|
|||
}
|
||||
|
||||
# These are automatic variables in PowerShell Core, but not in Windows PowerShell 5.x
|
||||
if (-not (Test-Path variable:global:ismacos)) {
|
||||
if (-not (Test-Path variable:global:IsMacOS)) {
|
||||
$IsLinux = $false
|
||||
$IsMacOS = $false
|
||||
}
|
||||
|
@ -266,4 +272,12 @@ $cakeArguments += $ScriptArgs
|
|||
# Start Cake
|
||||
Write-Host "Running build script..."
|
||||
Invoke-Expression "& $CAKE_EXE_INVOCATION $($cakeArguments -join " ")"
|
||||
exit $LASTEXITCODE
|
||||
$cakeExitCode = $LASTEXITCODE
|
||||
|
||||
# Clean up environment variables that were created earlier in this bootstrapper
|
||||
$env:CAKE_PATHS_TOOLS = $null
|
||||
$env:CAKE_PATHS_ADDINS = $null
|
||||
$env:CAKE_PATHS_MODULES = $null
|
||||
|
||||
# Return exit code
|
||||
exit $cakeExitCode
|
||||
|
|
Загрузка…
Ссылка в новой задаче