diff --git a/CommunityToolkit.Authentication.Msal/CommunityToolkit.Authentication.Msal.csproj b/CommunityToolkit.Authentication.Msal/CommunityToolkit.Authentication.Msal.csproj index 3024215..6b1ff0b 100644 --- a/CommunityToolkit.Authentication.Msal/CommunityToolkit.Authentication.Msal.csproj +++ b/CommunityToolkit.Authentication.Msal/CommunityToolkit.Authentication.Msal.csproj @@ -5,6 +5,7 @@ Windows Community Toolkit .NET Standard Auth Services This package includes .NET Standard authentication helpers such as: + - MsalProvider: Community Toolkit Provider Authentication Auth Msal diff --git a/CommunityToolkit.Authentication.Uwp/CommunityToolkit.Authentication.Uwp.csproj b/CommunityToolkit.Authentication.Uwp/CommunityToolkit.Authentication.Uwp.csproj index d6d0735..40c0024 100644 --- a/CommunityToolkit.Authentication.Uwp/CommunityToolkit.Authentication.Uwp.csproj +++ b/CommunityToolkit.Authentication.Uwp/CommunityToolkit.Authentication.Uwp.csproj @@ -8,7 +8,7 @@ This library provides an authentication provider based on the native Windows dialogues. It is part of the Windows Community Toolkit. Classes: - - WindowsProvider: + - WindowsProvider: Lightweight authentication provider built around the native Windows Account Manager (WAM) APIs. UWP Toolkit Windows Microsoft Graph AadLogin Authentication Login false diff --git a/CommunityToolkit.Graph.Uwp/Assets/person.png b/CommunityToolkit.Graph.Uwp/Assets/person.png deleted file mode 100644 index 3566862..0000000 Binary files a/CommunityToolkit.Graph.Uwp/Assets/person.png and /dev/null differ diff --git a/CommunityToolkit.Graph.Uwp/CommunityToolkit.Graph.Uwp.csproj b/CommunityToolkit.Graph.Uwp/CommunityToolkit.Graph.Uwp.csproj deleted file mode 100644 index 46262c7..0000000 --- a/CommunityToolkit.Graph.Uwp/CommunityToolkit.Graph.Uwp.csproj +++ /dev/null @@ -1,66 +0,0 @@ - - - - uap10.0.17763 - Windows Community Toolkit Graph Uwp Controls and Helpers - CommunityToolkit.Uwp.Graph.Controls - - This library provides Microsoft Graph UWP XAML controls. It is part of the Windows Community Toolkit. - - Classes: - - GraphPresenter: - - LoginButton: The Login Control leverages MSAL libraries to support the sign-in processes for Microsoft Graph and beyond. - - PersonView: The PersonView control displays a user photo and can display their name and e-mail. - - PeoplePicker: The PeoplePicker Control is a simple control that allows for selection of one or more users. - - UWP Toolkit Windows Controls MSAL Microsoft Graph AadLogin ProfileCard Person PeoplePicker Login - false - true - 9.0 - Debug;Release;CI - AnyCPU;ARM;ARM64;x64;x86 - - - - - - - - - - - - - - - - - - - - - - - - - - - - MSBuild:Compile - - - - - $(DefineConstants);WINRT - - - - - - - - - - - - diff --git a/CommunityToolkit.Graph.Uwp/Controls/GraphPresenter/GraphPresenter.cs b/CommunityToolkit.Graph.Uwp/Controls/GraphPresenter/GraphPresenter.cs deleted file mode 100644 index 484d24f..0000000 --- a/CommunityToolkit.Graph.Uwp/Controls/GraphPresenter/GraphPresenter.cs +++ /dev/null @@ -1,117 +0,0 @@ -// 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; -using Microsoft.Graph; -using Microsoft.Toolkit.Uwp; -using Newtonsoft.Json.Linq; -using Windows.System; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; - -namespace CommunityToolkit.Graph.Uwp.Controls -{ - /// - /// Specialized to fetch and display data from the Microsoft Graph. - /// - public class GraphPresenter : ContentPresenter - { - /// - /// Gets or sets a to be used to make a request to the graph. The results will be automatically populated to the property. Use a to change the presentation of the data. - /// - public IBaseRequestBuilder RequestBuilder - { - get { return (IBaseRequestBuilder)GetValue(RequestBuilderProperty); } - set { SetValue(RequestBuilderProperty, value); } - } - - /// - /// Identifies the dependency property. - /// - /// - /// The identifier for the dependency property. - /// - public static readonly DependencyProperty RequestBuilderProperty = - DependencyProperty.Register(nameof(RequestBuilder), typeof(IBaseRequestBuilder), typeof(GraphPresenter), new PropertyMetadata(null)); - - /// - /// Gets or sets the of item returned by the . - /// Set to the base item type and use the property to indicate if a collection is expected back. - /// - public Type ResponseType { get; set; } - - /// - /// Gets or sets a value indicating whether the returned data from the is a collection. - /// - public bool IsCollection { get; set; } - - /// - /// Gets or sets list of representing values to pass into the request built by . - /// - public List QueryOptions { get; set; } = new List(); - - /// - /// Gets or sets a string to indicate a sorting order for the . This is a helper to add this specific request option to the . - /// - public string OrderBy { get; set; } - - /// - /// Initializes a new instance of the class. - /// - public GraphPresenter() - { - Loaded += GraphPresenter_Loaded; - } - - private async void GraphPresenter_Loaded(object sender, RoutedEventArgs e) - { - var dispatcherQueue = DispatcherQueue.GetForCurrentThread(); - - // Note: some interfaces from the Graph SDK don't implement IBaseRequestBuilder properly, see https://github.com/microsoftgraph/msgraph-sdk-dotnet/issues/722 - if (RequestBuilder != null) - { - var request = new BaseRequest( - RequestBuilder.RequestUrl, - RequestBuilder.Client); // TODO: Do we need separate Options here? - ////request.Method = HttpMethods.GET; - request.Method = "GET"; - request.QueryOptions = QueryOptions?.Select(option => (Microsoft.Graph.QueryOption)option)?.ToList() ?? new List(); - - // Handle Special QueryOptions - if (!string.IsNullOrWhiteSpace(OrderBy)) - { - request.QueryOptions.Add(new Microsoft.Graph.QueryOption("$orderby", OrderBy)); - } - - try - { - var response = await request.SendAsync(null, CancellationToken.None).ConfigureAwait(false) as JObject; - - //// TODO: Deal with paging? - - var values = response["value"]; - object data = null; - - if (IsCollection) - { - data = values.ToObject(Array.CreateInstance(ResponseType, 0).GetType()); - } - else - { - data = values.ToObject(ResponseType); - } - - _ = dispatcherQueue.EnqueueAsync(() => Content = data); - } - catch - { - // TODO: We should figure out what we want to do for Loading/Error states here. - } - } - } - } -} \ No newline at end of file diff --git a/CommunityToolkit.Graph.Uwp/Controls/GraphPresenter/QueryOption.cs b/CommunityToolkit.Graph.Uwp/Controls/GraphPresenter/QueryOption.cs deleted file mode 100644 index 9486c28..0000000 --- a/CommunityToolkit.Graph.Uwp/Controls/GraphPresenter/QueryOption.cs +++ /dev/null @@ -1,34 +0,0 @@ -// 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.Text; -using System.Threading.Tasks; -using Windows.UI.Xaml; - -namespace CommunityToolkit.Graph.Uwp.Controls -{ - /// - /// XAML Proxy for . - /// - public sealed class QueryOption - { - /// - public string Name { get; set; } - - /// - public string Value { get; set; } - - /// - /// Implicit conversion for to . - /// - /// query option to convert. - public static implicit operator Microsoft.Graph.QueryOption(QueryOption option) - { - return new Microsoft.Graph.QueryOption(option.Name, option.Value); - } - } -} diff --git a/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.Events.cs b/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.Events.cs deleted file mode 100644 index a5ba998..0000000 --- a/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.Events.cs +++ /dev/null @@ -1,40 +0,0 @@ -// 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.ComponentModel; - -namespace CommunityToolkit.Graph.Uwp.Controls -{ - /// - /// The control is a button which can be used to sign the user in or show them profile details. - /// - public partial class LoginButton - { - /// - /// The user clicked the sign in button to start the login process - cancelable. - /// - public event CancelEventHandler LoginInitiated; - - /// - /// The login process was successful and the user is now signed in. - /// - public event EventHandler LoginCompleted; - - /// - /// The user canceled the login process or was unable to sign in. - /// - public event EventHandler LoginFailed; - - /// - /// The user started to logout - cancelable. - /// - public event CancelEventHandler LogoutInitiated; - - /// - /// The user signed out. - /// - public event EventHandler LogoutCompleted; - } -} diff --git a/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.Properties.cs b/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.Properties.cs deleted file mode 100644 index addd2f8..0000000 --- a/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.Properties.cs +++ /dev/null @@ -1,51 +0,0 @@ -// 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.Graph; -using Windows.UI.Xaml; - -namespace CommunityToolkit.Graph.Uwp.Controls -{ - /// - /// The control is a button which can be used to sign the user in or show them profile details. - /// - public partial class LoginButton - { - /// - /// Gets or sets details about this person retrieved from the graph or provided by the developer. - /// - public User UserDetails - { - get { return (User)GetValue(UserDetailsProperty); } - set { SetValue(UserDetailsProperty, value); } - } - - /// - /// Identifies the dependency property. - /// - /// - /// The identifier for the dependency property. - /// - public static readonly DependencyProperty UserDetailsProperty = - DependencyProperty.Register(nameof(UserDetails), typeof(User), typeof(LoginButton), new PropertyMetadata(null)); - - /// - /// Gets or sets a value indicating whether the control is loading and has not established a sign-in state. - /// - public bool IsLoading - { - get { return (bool)GetValue(IsLoadingProperty); } - protected set { SetValue(IsLoadingProperty, value); } - } - - /// - /// Identifies the dependency property. - /// - /// - /// The identifier for the dependency property. - /// - public static readonly DependencyProperty IsLoadingProperty = - DependencyProperty.Register(nameof(IsLoading), typeof(bool), typeof(LoginButton), new PropertyMetadata(true)); - } -} diff --git a/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.cs b/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.cs deleted file mode 100644 index f9acd1b..0000000 --- a/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.cs +++ /dev/null @@ -1,229 +0,0 @@ -// 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.ComponentModel; -using System.Diagnostics; -using System.Threading.Tasks; -using CommunityToolkit.Authentication; -using CommunityToolkit.Graph.Extensions; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Controls.Primitives; - -namespace CommunityToolkit.Graph.Uwp.Controls -{ - /// - /// The control is a button which can be used to sign the user in or show them profile details. - /// - [TemplatePart(Name = LoginButtonPart, Type = typeof(Button))] - [TemplatePart(Name = SignOutButtonPart, Type = typeof(ButtonBase))] - public partial class LoginButton : Control - { - private const string LoginButtonPart = "PART_LoginButton"; - private const string SignOutButtonPart = "PART_SignOutButton"; - - private Button _loginButton; - private ButtonBase _signOutButton; - - /// - /// Initializes a new instance of the class. - /// - public LoginButton() - { - this.DefaultStyleKey = typeof(LoginButton); - - ProviderManager.Instance.ProviderUpdated += (sender, args) => LoadData(); - } - - /// - protected override void OnApplyTemplate() - { - base.OnApplyTemplate(); - - IsLoading = true; - LoadData(); - - if (_loginButton != null) - { - _loginButton.Click -= LoginButton_Click; - } - - _loginButton = GetTemplateChild(LoginButtonPart) as Button; - - if (_loginButton != null) - { - _loginButton.Click += LoginButton_Click; - } - - if (_signOutButton != null) - { - _signOutButton.Click -= LoginButton_Click; - } - - _signOutButton = GetTemplateChild(SignOutButtonPart) as ButtonBase; - - if (_signOutButton != null) - { - _signOutButton.Click += SignOutButton_Click; - } - } - - private async void LoginButton_Click(object sender, RoutedEventArgs e) - { - if (this.UserDetails != null) - { - if (FlyoutBase.GetAttachedFlyout(_loginButton) is FlyoutBase flyout) - { - flyout.ShowAt(_loginButton); - } - } - else - { - var cargs = new CancelEventArgs(); - LoginInitiated?.Invoke(this, cargs); - - if (!cargs.Cancel) - { - await SignInAsync(); - } - } - } - - private async void SignOutButton_Click(object sender, RoutedEventArgs e) - { - await SignOutAsync(); - } - - private async void LoadData() - { - var provider = ProviderManager.Instance.GlobalProvider; - - if (provider == null) - { - return; - } - - if (provider.State == ProviderState.Loading) - { - IsLoading = true; - } - else if (provider.State == ProviderState.SignedIn) - { - try - { - // https://github.com/microsoftgraph/microsoft-graph-toolkit/blob/master/src/components/mgt-login/mgt-login.ts#L139 - // TODO: Batch with photo request later? https://github.com/microsoftgraph/msgraph-sdk-dotnet-core/issues/29 - UserDetails = await provider.GetClient().GetMeAsync(); - } - catch (Exception e) - { - LoginFailed?.Invoke(this, new LoginFailedEventArgs(e)); - } - - IsLoading = false; - } - else if (provider.State == ProviderState.SignedOut) - { - UserDetails = null; // What if this was user provided? Should we not hook into these events then? - - IsLoading = false; - } - else - { - // Provider in Loading state - Debug.Fail("unsupported state"); - } - } - - /// - /// Initiates logging in with the current registered in the . - /// - /// A representing the asynchronous operation. - public async Task SignInAsync() - { - if (UserDetails != null || IsLoading) - { - return; - } - - var provider = ProviderManager.Instance.GlobalProvider; - - if (provider != null) - { - try - { - IsLoading = true; - await provider.SignInAsync(); - - if (provider.State == ProviderState.SignedIn) - { - // TODO: include user details? - LoginCompleted?.Invoke(this, new EventArgs()); - - LoadData(); - } - else - { - LoginFailed?.Invoke(this, new LoginFailedEventArgs(new TimeoutException("Login did not complete."))); - } - } - catch (Exception e) - { - LoginFailed?.Invoke(this, new LoginFailedEventArgs(e)); - } - finally - { - IsLoading = false; - } - } - } - - /// - /// Log a signed-in user out. - /// - /// A representing the asynchronous operation. - public async Task SignOutAsync() - { - // Close Menu - if (FlyoutBase.GetAttachedFlyout(_loginButton) is FlyoutBase flyout) - { - flyout.Hide(); - } - - if (IsLoading) - { - return; - } - - var cargs = new CancelEventArgs(); - LogoutInitiated?.Invoke(this, cargs); - - if (cargs.Cancel) - { - return; - } - - if (UserDetails != null) - { - UserDetails = null; - } - else - { - return; // No-op - } - - var provider = ProviderManager.Instance.GlobalProvider; - - if (provider != null) - { - IsLoading = true; - await provider.SignOutAsync(); - IsLoading = false; - - LogoutCompleted?.Invoke(this, new EventArgs()); - } - } - } -} diff --git a/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.xaml b/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.xaml deleted file mode 100644 index c15d51a..0000000 --- a/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.xaml +++ /dev/null @@ -1,60 +0,0 @@ - - - - - - - - diff --git a/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginFailedEventArgs.cs b/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginFailedEventArgs.cs deleted file mode 100644 index bb2c0dd..0000000 --- a/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginFailedEventArgs.cs +++ /dev/null @@ -1,50 +0,0 @@ -// 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; - -namespace CommunityToolkit.Graph.Uwp.Controls -{ - /// - /// for event. - /// - public class LoginFailedEventArgs : EventArgs - { - /// - /// Gets the exception which occured during login. - /// - public Exception Exception { get; private set; } - - /// - /// Gets the inner exception which occured during login. - /// - public Exception InnerException - { - get - { - return Exception?.InnerException; - } - } - - /// - /// Gets the error message of the inner error or error. - /// - public string Message - { - get - { - return Exception?.InnerException?.Message ?? Exception?.Message; - } - } - - /// - /// Initializes a new instance of the class. - /// - /// Exception encountered during login. - public LoginFailedEventArgs(Exception exception) - { - Exception = exception; - } - } -} \ No newline at end of file diff --git a/CommunityToolkit.Graph.Uwp/Controls/PeoplePicker/PeoplePicker.cs b/CommunityToolkit.Graph.Uwp/Controls/PeoplePicker/PeoplePicker.cs deleted file mode 100644 index 3203c87..0000000 --- a/CommunityToolkit.Graph.Uwp/Controls/PeoplePicker/PeoplePicker.cs +++ /dev/null @@ -1,118 +0,0 @@ -// 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; -using System.Collections.ObjectModel; -using System.Linq; -using CommunityToolkit.Authentication; -using CommunityToolkit.Graph.Extensions; -using Microsoft.Graph; -using Microsoft.Toolkit.Uwp.UI; -using Microsoft.Toolkit.Uwp.UI.Controls; -using Windows.System; -using Windows.UI.Xaml.Controls; - -namespace CommunityToolkit.Graph.Uwp.Controls -{ - /// - /// Control which allows user to search for a person or contact within Microsoft Graph. Built on top of . - /// - public partial class PeoplePicker : TokenizingTextBox - { - private DispatcherQueueTimer _typeTimer = null; - - /// - /// Initializes a new instance of the class. - /// - public PeoplePicker() - { - this.DefaultStyleKey = typeof(PeoplePicker); - - SuggestedItemsSource = new ObservableCollection(); - - TextChanged += TokenBox_TextChanged; - TokenItemAdding += TokenBox_TokenItemTokenItemAdding; - - _typeTimer = DispatcherQueue.GetForCurrentThread().CreateTimer(); - } - - private async void TokenBox_TokenItemTokenItemAdding(TokenizingTextBox sender, TokenItemAddingEventArgs args) - { - using (args.GetDeferral()) - { - // Try and convert typed text to people - var graph = ProviderManager.Instance.GlobalProvider.GetClient(); - if (graph != null) - { - args.Item = (await graph.FindPersonAsync(args.TokenText)).CurrentPage.FirstOrDefault(); - } - - // If we didn't find anyone, then don't add anyone. - if (args.Item == null) - { - args.Cancel = true; - - // TODO: We should raise a 'person not found' type event or automatically display some feedback? - } - } - } - - private void TokenBox_TextChanged(AutoSuggestBox sender, AutoSuggestBoxTextChangedEventArgs args) - { - if (!args.CheckCurrent()) - { - return; - } - - if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput) - { - var text = sender.Text; - var list = SuggestedItemsSource as IList; - - if (list != null) - { - _typeTimer.Debounce( - async () => - { - var graph = ProviderManager.Instance.GlobalProvider.GetClient(); - if (graph != null) - { - // If empty, will clear out - list.Clear(); - - if (!string.IsNullOrWhiteSpace(text)) - { - foreach (var user in (await graph.FindUserAsync(text)).CurrentPage) - { - // Exclude people in suggested list that we already have picked - if (!Items.Any(person => (person as Person)?.Id == user.Id)) - { - list.Add(user.ToPerson()); - } - } - - // Grab ids of current suggestions - var ids = list.Cast().Select(person => (person as Person).Id); - - foreach (var contact in (await graph.FindPersonAsync(text)).CurrentPage) - { - // Exclude people in suggested list that we already have picked - // Or already suggested - if (!Items.Any(person => (person as Person)?.Id == contact.Id) && - !ids.Any(id => id == contact.Id)) - { - list.Add(contact); - } - } - } - } - - // TODO: If we don't have Graph connection and just list of Person should we auto-filter here? - }, TimeSpan.FromSeconds(0.3)); - } - } - } - } -} diff --git a/CommunityToolkit.Graph.Uwp/Controls/PeoplePicker/PeoplePicker.xaml b/CommunityToolkit.Graph.Uwp/Controls/PeoplePicker/PeoplePicker.xaml deleted file mode 100644 index 4ad12dc..0000000 --- a/CommunityToolkit.Graph.Uwp/Controls/PeoplePicker/PeoplePicker.xaml +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - diff --git a/CommunityToolkit.Graph.Uwp/Controls/PersonView/PersonView.Properties.cs b/CommunityToolkit.Graph.Uwp/Controls/PersonView/PersonView.Properties.cs deleted file mode 100644 index 1b47d42..0000000 --- a/CommunityToolkit.Graph.Uwp/Controls/PersonView/PersonView.Properties.cs +++ /dev/null @@ -1,139 +0,0 @@ -// 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.Graph; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Media.Imaging; - -namespace CommunityToolkit.Graph.Uwp.Controls -{ - /// - /// The control displays a user photo and can display their name and e-mail. - /// - public partial class PersonView - { - /// - /// Gets or sets details about this person retrieved from the graph or provided by the developer. - /// - public Person PersonDetails - { - get { return (Person)GetValue(PersonDetailsProperty); } - set { SetValue(PersonDetailsProperty, value); } - } - - /// - /// Identifies the dependency property. - /// - /// - /// The identifier for the dependency property. - /// - public static readonly DependencyProperty PersonDetailsProperty = - DependencyProperty.Register(nameof(PersonDetails), typeof(Person), typeof(PersonView), new PropertyMetadata(null, PersonDetailsPropertyChanged)); - - /// - /// Gets or sets a string to automatically retrieve data on the specified query from the graph. Use to retrieve info about the current user. Otherwise, it's best to use an e-mail address as a query. - /// - public string PersonQuery - { - get { return (string)GetValue(PersonQueryProperty); } - set { SetValue(PersonQueryProperty, value); } - } - - /// - /// Identifies the dependency property. - /// - /// - /// The identifier for the dependency property. - /// - public static readonly DependencyProperty PersonQueryProperty = - DependencyProperty.Register(nameof(PersonQuery), typeof(string), typeof(PersonView), new PropertyMetadata(null, QueryPropertyChanged)); - - /// - /// Gets or sets the UserId. - /// - public string UserId - { - get { return (string)GetValue(UserIdProperty); } - set { SetValue(UserIdProperty, value); } - } - - /// - /// Identifies the dependency property. - /// - /// - /// The identifier for the dependency property. - /// - public static readonly DependencyProperty UserIdProperty = - DependencyProperty.Register(nameof(UserId), typeof(string), typeof(PersonView), new PropertyMetadata(null, QueryPropertyChanged)); - - /// - /// Gets or sets the photo of the user to be displayed. - /// - public BitmapImage UserPhoto - { - get { return (BitmapImage)GetValue(UserPhotoProperty); } - set { SetValue(UserPhotoProperty, value); } - } - - /// - /// Identifies the dependency property. - /// - /// - /// The identifier for the dependency property. - /// - public static readonly DependencyProperty UserPhotoProperty = - DependencyProperty.Register(nameof(UserPhoto), typeof(BitmapImage), typeof(PersonView), new PropertyMetadata(null)); - - /// - /// Gets the initials of the person from the . - /// - public string Initials - { - get { return (string)GetValue(InitialsProperty); } - internal set { SetValue(InitialsProperty, value); } - } - - /// - /// Identifies the dependency property. - /// - /// - /// The identifier for the dependency property. - /// - public static readonly DependencyProperty InitialsProperty = - DependencyProperty.Register(nameof(Initials), typeof(string), typeof(PersonView), new PropertyMetadata(string.Empty)); - - /// - /// Gets a value indicating whether the image has expanded based on the PersonViewType. - /// - public bool IsLargeImage - { - get { return (bool)GetValue(IsLargeImageProperty); } - internal set { SetValue(IsLargeImageProperty, value); } - } - - /// - /// Identifies the dependency property. - /// - /// - /// The identifier for the dependency property. - /// - public static readonly DependencyProperty IsLargeImageProperty = - DependencyProperty.Register(nameof(IsLargeImage), typeof(bool), typeof(PersonView), new PropertyMetadata(false)); - - /// - /// Gets or sets the type of details to display in the PersonView part of the template. - /// - public PersonViewType PersonViewType - { - get => (PersonViewType)GetValue(PersonViewTypeProperty); - set => SetValue(PersonViewTypeProperty, value); - } - - /// - /// Identifies the dependency property. - /// - public static readonly DependencyProperty PersonViewTypeProperty = - DependencyProperty.Register(nameof(PersonViewType), typeof(PersonViewType), typeof(PersonView), new PropertyMetadata(PersonViewType.TwoLines, PersonViewTypePropertiesChanged)); - } -} diff --git a/CommunityToolkit.Graph.Uwp/Controls/PersonView/PersonView.cs b/CommunityToolkit.Graph.Uwp/Controls/PersonView/PersonView.cs deleted file mode 100644 index 5ef9e4a..0000000 --- a/CommunityToolkit.Graph.Uwp/Controls/PersonView/PersonView.cs +++ /dev/null @@ -1,228 +0,0 @@ -// 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.IO; -using System.Linq; -using System.Threading.Tasks; -using CommunityToolkit.Authentication; -using CommunityToolkit.Graph.Extensions; -using Microsoft.Graph; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Media.Imaging; - -namespace CommunityToolkit.Graph.Uwp.Controls -{ - /// - /// The control displays a user photo and can display their name and e-mail. - /// - public partial class PersonView : Control - { - private const string PersonViewDefaultImageSourceResourceName = "PersonViewDefaultImageSource"; - - /// - /// value used to retrieve the signed-in user's info. - /// - public const string PersonQueryMe = "me"; - - private string _photoId = null; - - private string _defaultImageSource = "ms-appx:///Microsoft.Toolkit.Graph.Controls/Assets/person.png"; - - private BitmapImage _defaultImage; - - private static async void PersonDetailsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if (d is PersonView pv) - { - if (pv.PersonDetails != null) - { - if (pv?.PersonDetails?.GivenName?.Length > 0 && pv?.PersonDetails?.Surname?.Length > 0) - { - pv.Initials = string.Empty + pv.PersonDetails.GivenName[0] + pv.PersonDetails.Surname[0]; - } - else if (pv?.PersonDetails?.DisplayName?.Length > 0) - { - // Grab first two initials in name - var initials = pv.PersonDetails.DisplayName.ToUpper().Split(' ').Select(i => i.First()); - pv.Initials = string.Join(string.Empty, initials.Where(i => char.IsLetter(i)).Take(2)); - } - - if (pv?.UserPhoto?.UriSource?.AbsoluteUri == pv._defaultImageSource || pv?.PersonDetails?.Id != pv._photoId) - { - // Reload Image - pv.UserPhoto = pv._defaultImage; - await pv.LoadImageAsync(pv.PersonDetails); - } - else if (pv?.PersonDetails?.Id != pv._photoId) - { - pv.UserPhoto = pv._defaultImage; - pv._photoId = null; - } - } - } - } - - private static void QueryPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if (d is PersonView view) - { - view.PersonDetails = null; - view.LoadData(); - } - } - - private static void PersonViewTypePropertiesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if (d is PersonView pv) - { - pv.IsLargeImage = pv.PersonViewType == PersonViewType.Avatar; - } - } - - /// - /// Initializes a new instance of the class. - /// - public PersonView() - { - this.DefaultStyleKey = typeof(PersonView); - - _defaultImage = new BitmapImage(new Uri(_defaultImageSource)); - - ProviderManager.Instance.ProviderUpdated += (sender, args) => LoadData(); - } - - /// - protected override void OnApplyTemplate() - { - base.OnApplyTemplate(); - - if (Resources.TryGetValue(PersonViewDefaultImageSourceResourceName, out object value) && value is string uri) - { - _defaultImageSource = uri; - _defaultImage = new BitmapImage(new Uri(_defaultImageSource)); // TODO: Couldn't load image from app package, only remote or in our assembly? - UserPhoto = _defaultImage; - } - - LoadData(); - } - - private async void LoadData() - { - var provider = ProviderManager.Instance.GlobalProvider; - - if (provider == null || provider.State != ProviderState.SignedIn) - { - // Set back to Default if not signed-in - if (provider != null) - { - UserPhoto = _defaultImage; - } - - return; - } - - if (PersonDetails != null && UserPhoto == null) - { - await LoadImageAsync(PersonDetails); - } - else if (!string.IsNullOrWhiteSpace(UserId) || PersonQuery?.ToLowerInvariant() == PersonQueryMe) - { - User user = null; - if (!string.IsNullOrWhiteSpace(UserId)) - { - // TODO: Batch when API easier https://github.com/microsoftgraph/msgraph-sdk-dotnet-core/issues/29 - try - { - user = await provider.GetClient().GetUserAsync(UserId); - } - catch - { - } - - try - { - // TODO: Move to LoadImage based on previous call? - await DecodeStreamAsync(await provider.GetBetaClient().GetUserPhoto(UserId)); - _photoId = UserId; - } - catch - { - } - } - else - { - try - { - user = await provider.GetClient().GetMeAsync(); - } - catch - { - } - - try - { - await DecodeStreamAsync(await provider.GetBetaClient().GetMyPhotoAsync()); - _photoId = user.Id; - } - catch - { - } - } - - if (user != null) - { - PersonDetails = user.ToPerson(); - } - } - else if (PersonDetails == null && !string.IsNullOrWhiteSpace(PersonQuery)) - { - var people = await provider.GetClient().FindPersonAsync(PersonQuery); - if (people != null && people.Count > 0) - { - var person = people.FirstOrDefault(); - PersonDetails = person; - await LoadImageAsync(person); - } - } - } - - private async Task LoadImageAsync(Person person) - { - try - { - // TODO: Better guarding - var graph = ProviderManager.Instance.GlobalProvider.GetBetaClient(); - - if (!string.IsNullOrWhiteSpace(person.UserPrincipalName)) - { - await DecodeStreamAsync(await graph.GetUserPhoto(person.UserPrincipalName)); - _photoId = person.Id; // TODO: Only set on success for photo? - } - else if (!string.IsNullOrWhiteSpace(person.ScoredEmailAddresses.First().Address)) - { - // TODO https://github.com/microsoftgraph/microsoft-graph-toolkit/blob/master/src/components/mgt-person/mgt-person.ts#L174 - } - } - catch - { - // If we can't load a photo, that's ok. - } - } - - private async Task DecodeStreamAsync(Stream photoStream) - { - if (photoStream != null) - { - using (var ras = photoStream.AsRandomAccessStream()) - { - var bitmap = new BitmapImage(); - await bitmap.SetSourceAsync(ras); - UserPhoto = bitmap; - } - } - } - } -} diff --git a/CommunityToolkit.Graph.Uwp/Controls/PersonView/PersonView.xaml b/CommunityToolkit.Graph.Uwp/Controls/PersonView/PersonView.xaml deleted file mode 100644 index b9988f3..0000000 --- a/CommunityToolkit.Graph.Uwp/Controls/PersonView/PersonView.xaml +++ /dev/null @@ -1,96 +0,0 @@ - - - - - - - - - ms-appx:///Microsoft.Toolkit.Graph.Controls/Assets/person.png - - - diff --git a/CommunityToolkit.Graph.Uwp/Controls/PersonView/PersonViewType.cs b/CommunityToolkit.Graph.Uwp/Controls/PersonView/PersonViewType.cs deleted file mode 100644 index d80c36b..0000000 --- a/CommunityToolkit.Graph.Uwp/Controls/PersonView/PersonViewType.cs +++ /dev/null @@ -1,27 +0,0 @@ -// 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.Graph.Uwp.Controls -{ - /// - /// Enumeration of what details should be displayed in a PersonView. - /// - public enum PersonViewType - { - /** - * Render only the avatar - */ - Avatar = 0, - - /** - * Render the avatar and one line of text - */ - OneLine = 1, - - /** - * Render the avatar and two lines of text - */ - TwoLines = 2, - } -} diff --git a/CommunityToolkit.Graph.Uwp/Converters/ObjectToStringConverter.cs b/CommunityToolkit.Graph.Uwp/Converters/ObjectToStringConverter.cs deleted file mode 100644 index b6d8707..0000000 --- a/CommunityToolkit.Graph.Uwp/Converters/ObjectToStringConverter.cs +++ /dev/null @@ -1,27 +0,0 @@ -// 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 Windows.UI.Xaml.Data; - -namespace CommunityToolkit.Graph.Uwp.Converters -{ - /// - /// Converts any object to a string representation. - /// - public class ObjectToStringConverter : IValueConverter - { - /// - public object Convert(object value, Type targetType, object parameter, string language) - { - return value.ToString(); - } - - /// - public object ConvertBack(object value, Type targetType, object parameter, string language) - { - throw new NotImplementedException(); - } - } -} diff --git a/CommunityToolkit.Graph.Uwp/Converters/UserToPersonConverter.cs b/CommunityToolkit.Graph.Uwp/Converters/UserToPersonConverter.cs deleted file mode 100644 index bdb88fb..0000000 --- a/CommunityToolkit.Graph.Uwp/Converters/UserToPersonConverter.cs +++ /dev/null @@ -1,34 +0,0 @@ -// 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 CommunityToolkit.Graph.Extensions; -using Microsoft.Graph; -using Windows.UI.Xaml.Data; - -namespace CommunityToolkit.Graph.Uwp.Converters -{ - /// - /// Converts a to a . - /// - public class UserToPersonConverter : IValueConverter - { - /// - public object Convert(object value, Type targetType, object parameter, string language) - { - if (value is User user) - { - return user.ToPerson(); - } - - return null; - } - - /// - public object ConvertBack(object value, Type targetType, object parameter, string language) - { - throw new NotImplementedException(); - } - } -} diff --git a/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/BaseRoamingSettingsDataStore.cs b/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/BaseRoamingSettingsDataStore.cs deleted file mode 100644 index b3109d1..0000000 --- a/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/BaseRoamingSettingsDataStore.cs +++ /dev/null @@ -1,303 +0,0 @@ -// 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.Reflection; -using System.Threading.Tasks; -using Microsoft.Toolkit.Uwp.Helpers; -using Windows.Storage; - -namespace CommunityToolkit.Uwp.Graph.Helpers.RoamingSettings -{ - /// - /// A base class for easily building roaming settings helper implementations. - /// - public abstract class BaseRoamingSettingsDataStore : IRoamingSettingsDataStore - { - /// - public EventHandler SyncCompleted { get; set; } - - /// - public EventHandler SyncFailed { get; set; } - - /// - public bool AutoSync { get; } - - /// - public string Id { get; } - - /// - public string UserId { get; } - - /// - public IDictionary Cache { get; private set; } = new Dictionary(); - - /// - /// Gets an object serializer for converting objects in the data store. - /// - protected IObjectSerializer Serializer { get; } - - /// - /// Initializes a new instance of the class. - /// - /// The id of the target Graph user. - /// A unique id for the data store. - /// An IObjectSerializer used for serializing objects. - /// Determines if the data store should sync for every interaction. - public BaseRoamingSettingsDataStore(string userId, string dataStoreId, IObjectSerializer objectSerializer, bool autoSync = true) - { - AutoSync = autoSync; - Id = dataStoreId; - UserId = userId; - Serializer = objectSerializer; - } - - /// - /// Create a new instance of the data storage container. - /// - /// A task. - public abstract Task Create(); - - /// - /// Delete the instance of the data storage container. - /// - /// A task. - public abstract Task Delete(); - - /// - /// Determines whether a setting already exists. - /// - /// Key of the setting (that contains object). - /// True if a value exists. - public bool KeyExists(string key) - { - return Cache?.ContainsKey(key) ?? false; - } - - /// - /// Determines whether a setting already exists in composite. - /// - /// Key of the composite (that contains settings). - /// Key of the setting (that contains object). - /// True if a value exists. - public bool KeyExists(string compositeKey, string key) - { - if (KeyExists(compositeKey)) - { - ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)Cache[compositeKey]; - if (composite != null) - { - return composite.ContainsKey(key); - } - } - - return false; - } - - /// - /// Retrieves a single item by its key. - /// - /// Key of the object. - /// Default value of the object. - /// Type of object retrieved. - /// The T object. - public T Read(string key, T @default = default) - { - if (Cache != null && Cache.TryGetValue(key, out object value)) - { - return DeserializeValue(value); - } - - return @default; - } - - /// - /// Retrieves a single item by its key in composite. - /// - /// Key of the composite (that contains settings). - /// Key of the object. - /// Default value of the object. - /// Type of object retrieved. - /// The T object. - public T Read(string compositeKey, string key, T @default = default) - { - if (Cache != null) - { - ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)Cache[compositeKey]; - if (composite != null) - { - object value = composite[key]; - if (value != null) - { - return DeserializeValue(value); - } - } - } - - return @default; - } - - /// - /// Saves a single item by its key. - /// - /// Key of the value saved. - /// Object to save. - /// Type of object saved. - public void Save(string key, T value) - { - // Update the cache - Cache[key] = SerializeValue(value); - - if (AutoSync) - { - // Update the remote - Task.Run(() => Sync()); - } - } - - /// - /// 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 - /// (refers to Microsoft.Toolkit.Uwp.Helpers.IObjectStorageHelper.SaveFileAsync``1(System.String,``0) - /// for complex/large objects) and for groups of settings which need to be treated - /// in an atomic way. - /// - /// Key of the composite (that contains settings). - /// Objects to save. - /// Type of object saved. - public void Save(string compositeKey, IDictionary values) - { - var type = typeof(T); - var typeInfo = type.GetTypeInfo(); - - if (KeyExists(compositeKey)) - { - ApplicationDataCompositeValue composite = (ApplicationDataCompositeValue)Cache[compositeKey]; - - foreach (KeyValuePair setting in values.ToList()) - { - string key = setting.Key; - object value = SerializeValue(setting.Value); - if (composite.ContainsKey(setting.Key)) - { - composite[key] = value; - } - else - { - composite.Add(key, value); - } - } - - // Update the cache - Cache[compositeKey] = composite; - - if (AutoSync) - { - // Update the remote - Task.Run(() => Sync()); - } - } - else - { - ApplicationDataCompositeValue composite = new ApplicationDataCompositeValue(); - foreach (KeyValuePair setting in values.ToList()) - { - string key = setting.Key; - object value = SerializeValue(setting.Value); - composite.Add(key, value); - } - - // Update the cache - Cache[compositeKey] = composite; - - if (AutoSync) - { - // Update the remote - Task.Run(() => Sync()); - } - } - } - - /// - /// Determines whether a file already exists. - /// - /// Key of the file (that contains object). - /// True if a value exists. - public abstract Task FileExistsAsync(string filePath); - - /// - /// Retrieves an object from a file. - /// - /// Path to the file that contains the object. - /// Default value of the object. - /// Type of object retrieved. - /// Waiting task until completion with the object in the file. - public abstract Task ReadFileAsync(string filePath, T @default = default); - - /// - /// Saves an object inside a file. - /// - /// Path to the file that will contain the object. - /// Object to save. - /// Type of object saved. - /// Waiting task until completion. - public abstract Task SaveFileAsync(string filePath, T value); - - /// - public abstract Task Sync(); - - /// - /// Delete the internal cache. - /// - protected void DeleteCache() - { - Cache.Clear(); - } - - /// - /// Use the serializer to deserialize a value appropriately for the type. - /// - /// The type of object expected. - /// The value to deserialize. - /// An object of type T. - protected T DeserializeValue(object value) - { - try - { - return Serializer.Deserialize((string)value); - } - catch - { - // Primitive types can't be deserialized. - return (T)Convert.ChangeType(value, typeof(T)); - } - } - - /// - /// Use the serializer to serialize a value appropriately for the type. - /// - /// The type of object being serialized. - /// The object to serialize. - /// The serialized object. - protected object SerializeValue(T value) - { - var type = typeof(T); - var typeInfo = type.GetTypeInfo(); - - // Skip serialization for primitives. - if (typeInfo.IsPrimitive || type == typeof(string)) - { - // Update the cache - return value; - } - else - { - // Update the cache - return Serializer.Serialize(value); - } - } - } -} diff --git a/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/IRoamingSettingsDataStore.cs b/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/IRoamingSettingsDataStore.cs deleted file mode 100644 index d5b8a67..0000000 --- a/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/IRoamingSettingsDataStore.cs +++ /dev/null @@ -1,65 +0,0 @@ -// 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 Microsoft.Toolkit.Uwp.Helpers; - -namespace CommunityToolkit.Uwp.Graph.Helpers.RoamingSettings -{ - /// - /// Defines the contract for creating storage containers used for roaming data. - /// - public interface IRoamingSettingsDataStore : IObjectStorageHelper - { - /// - /// Gets a value indicating whether the values should immediately sync or not. - /// - bool AutoSync { get; } - - /// - /// Gets access to the key/value pairs cache directly. - /// - IDictionary Cache { get; } - - /// - /// Gets the id of the data store. - /// - string Id { get; } - - /// - /// Gets the id of the target user. - /// - string UserId { get; } - - /// - /// Gets or sets an event handler for when a remote data sync completes successfully. - /// - EventHandler SyncCompleted { get; set; } - - /// - /// Gets or sets an event handler for when a remote data sync fails. - /// - EventHandler SyncFailed { get; set; } - - /// - /// Create a new storage container. - /// - /// A Task. - Task Create(); - - /// - /// Delete the existing storage container. - /// - /// A Task. - Task Delete(); - - /// - /// Syncronize the internal cache with the remote storage endpoint. - /// - /// A Task. - Task Sync(); - } -} \ No newline at end of file diff --git a/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/OneDriveDataSource.cs b/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/OneDriveDataSource.cs deleted file mode 100644 index f5a0c66..0000000 --- a/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/OneDriveDataSource.cs +++ /dev/null @@ -1,69 +0,0 @@ -// 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.IO; -using System.Text; -using System.Threading.Tasks; -using CommunityToolkit.Authentication; -using CommunityToolkit.Graph.Extensions; -using Microsoft.Graph; -using Microsoft.Toolkit.Uwp.Helpers; - -namespace CommunityToolkit.Uwp.Graph.Helpers.RoamingSettings -{ - /// - /// Helpers for interacting with files in the special OneDrive AppRoot folder. - /// - internal static class OneDriveDataSource - { - private static GraphServiceClient Graph => ProviderManager.Instance.GlobalProvider?.GetClient(); - - // Create a new file. - // This fails, because OneDrive doesn't like empty files. Use Update instead. - // public static async Task Create(string fileWithExt) - // { - // var driveItem = new DriveItem() - // { - // Name = fileWithExt, - // }; - // await Graph.Users[userId].Drive.Special.AppRoot.ItemWithPath(fileWithExt).Request().CreateAsync(driveItem); - // } - - /// - /// Updates or create a new file on the remote with the provided content. - /// - /// The type of object to save. - /// A representing the asynchronous operation. - public static async Task Update(string userId, string fileWithExt, T fileContents, IObjectSerializer serializer) - { - var json = serializer.Serialize(fileContents) as string; - using var stream = new MemoryStream(Encoding.UTF8.GetBytes(json)); - - return await Graph.Users[userId].Drive.Special.AppRoot.ItemWithPath(fileWithExt).Content.Request().PutAsync(stream); - } - - /// - /// Get a file from the remote. - /// - /// The type of object to return. - /// A representing the asynchronous operation. - public static async Task Retrieve(string userId, string fileWithExt, IObjectSerializer serializer) - { - Stream stream = await Graph.Users[userId].Drive.Special.AppRoot.ItemWithPath(fileWithExt).Content.Request().GetAsync(); - - string streamContents = new StreamReader(stream).ReadToEnd(); - - return serializer.Deserialize(streamContents); - } - - /// - /// Delete the file from the remote. - /// - /// A representing the asynchronous operation. - public static async Task Delete(string userId, string fileWithExt) - { - await Graph.Users[userId].Drive.Special.AppRoot.ItemWithPath(fileWithExt).Request().DeleteAsync(); - } - } -} diff --git a/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/OneDriveDataStore.cs b/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/OneDriveDataStore.cs deleted file mode 100644 index c3b7063..0000000 --- a/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/OneDriveDataStore.cs +++ /dev/null @@ -1,154 +0,0 @@ -// 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 Microsoft.Toolkit.Uwp.Helpers; -using Windows.Storage; - -namespace CommunityToolkit.Uwp.Graph.Helpers.RoamingSettings -{ - /// - /// A DataStore for managing roaming settings in OneDrive. - /// - public class OneDriveDataStore : BaseRoamingSettingsDataStore - { - /// - /// Retrieve an object stored in a OneDrive file. - /// - /// The type of object to retrieve. - /// The id of the target Graph user. - /// The name of the file. - /// An object serializer for handling deserialization. - /// The deserialized file contents. - public static async Task Get(string userId, string fileName, IObjectSerializer serializer) - { - return await OneDriveDataSource.Retrieve(userId, fileName, serializer); - } - - /// - /// Update the contents of a OneDrive file. - /// - /// The type of object being stored. - /// The id of the target Graph user. - /// The name of the file. - /// The object to store. - /// An object serializer for handling serialization. - /// A task. - public static async Task Set(string userId, string fileName, T fileContents, IObjectSerializer serializer) - { - await OneDriveDataSource.Update(userId, fileName, fileContents, serializer); - } - - /// - /// Delete a file from OneDrive by name. - /// - /// The id of the target Graph user. - /// The name of the file. - /// A task. - public static async Task Delete(string userId, string fileName) - { - await OneDriveDataSource.Delete(userId, fileName); - } - - /// - /// Initializes a new instance of the class. - /// - public OneDriveDataStore(string userId, string syncDataFileName, IObjectSerializer objectSerializer, bool autoSync = true) - : base(userId, syncDataFileName, objectSerializer, autoSync) - { - } - - /// - public override Task Create() - { - return Task.CompletedTask; - } - - /// - public override async Task Delete() - { - // Clear the cache - Cache.Clear(); - - // Delete the remote. - await Delete(UserId, Id); - } - - /// - public override async Task FileExistsAsync(string filePath) - { - var roamingSettings = await Get(UserId, Id, Serializer); - return roamingSettings != null; - } - - /// - public override async Task ReadFileAsync(string filePath, T @default = default) - { - return await Get(UserId, filePath, Serializer) ?? @default; - } - - /// - public override async Task SaveFileAsync(string filePath, T value) - { - await Set(UserId, filePath, value, Serializer); - - // Can't convert DriveItem to StorageFile, so we return null instead. - return null; - } - - /// - public override async Task Sync() - { - try - { - // Get the remote - string fileName = Id; - IDictionary remoteData = null; - try - { - remoteData = await Get>(UserId, fileName, Serializer); - } - catch - { - // If get fails, we know the remote store does not exist. - } - - bool needsUpdate = false; - if (remoteData != null) - { - // Update local cache with additions from remote - foreach (string key in remoteData.Keys.ToList()) - { - // Only insert new values. Existing keys should be overwritten on the remote. - if (!Cache.ContainsKey(key)) - { - Cache.Add(key, remoteData[key]); - needsUpdate = true; - } - } - } - else if (Cache.Count > 0) - { - // The remote does not yet exist, and we have data to save. - needsUpdate = true; - } - - if (needsUpdate) - { - // Send updates for local values, overwriting the remote. - await Set(UserId, fileName, Cache, Serializer); - } - - SyncCompleted?.Invoke(this, new EventArgs()); - } - catch - { - SyncFailed?.Invoke(this, new EventArgs()); - } - } - } -} diff --git a/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/RoamingSettingsHelper.cs b/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/RoamingSettingsHelper.cs deleted file mode 100644 index c160e0d..0000000 --- a/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/RoamingSettingsHelper.cs +++ /dev/null @@ -1,188 +0,0 @@ -// 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.Authentication; -using CommunityToolkit.Graph.Extensions; -using Microsoft.Toolkit.Uwp.Helpers; -using Windows.Storage; - -namespace CommunityToolkit.Uwp.Graph.Helpers.RoamingSettings -{ - /// - /// An enumeration of the available data storage methods for roaming data. - /// - public enum RoamingDataStore - { - /// - /// Store data using open extensions on the Graph User. - /// - UserExtensions, - - /// - /// Store data in a Graph User's OneDrive. - /// - OneDrive, - } - - /// - /// A helper class for syncing data to roaming data store. - /// - public class RoamingSettingsHelper : IRoamingSettingsDataStore - { - /// - /// Gets the internal data store instance. - /// - public IRoamingSettingsDataStore DataStore { get; private set; } - - /// - public EventHandler SyncCompleted { get; set; } - - /// - public EventHandler SyncFailed { get; set; } - - /// - public bool AutoSync => DataStore.AutoSync; - - /// - public IDictionary Cache => DataStore.Cache; - - /// - public string Id => DataStore.Id; - - /// - public string UserId => DataStore.UserId; - - /// - /// Creates a new RoamingSettingsHelper instance for the currently signed in user. - /// - /// Which specific data store is being used. - /// Whether the values should immediately sync or not. - /// Whether the values should immediately sync on change or wait until Sync is called explicitly. - /// An object serializer for serialization of objects in the data store. - /// A new instance of the RoamingSettingsHelper configured for the current user. - public static async Task CreateForCurrentUser(RoamingDataStore dataStore = RoamingDataStore.UserExtensions, bool syncOnInit = true, bool autoSync = true, IObjectSerializer serializer = null) - { - var provider = ProviderManager.Instance.GlobalProvider; - if (provider == null || provider.State != ProviderState.SignedIn) - { - throw new InvalidOperationException("The GlobalProvider must be set and signed in to create a new RoamingSettingsHelper for the current user."); - } - - var me = await provider.GetClient().Me.Request().GetAsync(); - return new RoamingSettingsHelper(me.Id, dataStore, syncOnInit, autoSync, serializer); - } - - /// - /// Initializes a new instance of the class. - /// - /// The id of the target Graph User. - /// Which specific data store is being used. - /// Whether the values should immediately sync or not. - /// Whether the values should immediately sync on change or wait until Sync is called explicitly. - /// An object serializer for serialization of objects in the data store. - public RoamingSettingsHelper(string userId, RoamingDataStore dataStore = RoamingDataStore.UserExtensions, bool syncOnInit = true, bool autoSync = true, IObjectSerializer serializer = null) - { - // TODO: Infuse unique identifier from Graph registration into the storage name. - string dataStoreName = "communityToolkit.roamingSettings"; - - if (serializer == null) - { - serializer = new SystemSerializer(); - } - - switch (dataStore) - { - case RoamingDataStore.UserExtensions: - DataStore = new UserExtensionDataStore(userId, dataStoreName, serializer, autoSync); - break; - - case RoamingDataStore.OneDrive: - DataStore = new OneDriveDataStore(userId, dataStoreName, serializer, autoSync); - break; - - default: - throw new ArgumentOutOfRangeException(nameof(dataStore)); - } - - DataStore.SyncCompleted += (s, e) => SyncCompleted?.Invoke(this, e); - DataStore.SyncFailed += (s, e) => SyncFailed?.Invoke(this, e); - - if (syncOnInit) - { - _ = Sync(); - } - } - - /// - /// An indexer for easily accessing key values. - /// - /// The key for the desired value. - /// The value found for the provided key. - public object this[string key] - { - get => DataStore.Read(key); - set => DataStore.Save(key, value); - } - - /// - public Task FileExistsAsync(string filePath) => DataStore.FileExistsAsync(filePath); - - /// - public bool KeyExists(string key) => DataStore.KeyExists(key); - - /// - public bool KeyExists(string compositeKey, string key) => DataStore.KeyExists(compositeKey, key); - - /// - public T Read(string key, T @default = default) => DataStore.Read(key, @default); - - /// - public T Read(string compositeKey, string key, T @default = default) => DataStore.Read(compositeKey, key, @default); - - /// - public Task ReadFileAsync(string filePath, T @default = default) => DataStore.ReadFileAsync(filePath, @default); - - /// - public void Save(string key, T value) => DataStore.Save(key, value); - - /// - public void Save(string compositeKey, IDictionary values) => DataStore.Save(compositeKey, values); - - /// - public Task SaveFileAsync(string filePath, T value) => DataStore.SaveFileAsync(filePath, value); - - /// - /// Create a new storage container. - /// - /// A Task. - public Task Create() => DataStore.Create(); - - /// - /// Delete the existing storage container. - /// - /// A Task. - public Task Delete() => DataStore.Delete(); - - /// - /// Syncronize the internal cache with the remote storage endpoint. - /// - /// A Task. - public async Task Sync() - { - try - { - await DataStore.Sync(); - } - catch - { - // Sync may fail if the storage container does not yet exist. - await DataStore.Create(); - await DataStore.Sync(); - } - } - } -} \ No newline at end of file diff --git a/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/UserExtensionDataStore.cs b/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/UserExtensionDataStore.cs deleted file mode 100644 index ff4d884..0000000 --- a/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/UserExtensionDataStore.cs +++ /dev/null @@ -1,201 +0,0 @@ -// 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 Microsoft.Graph; -using Microsoft.Toolkit.Uwp.Helpers; -using Windows.Storage; - -namespace CommunityToolkit.Uwp.Graph.Helpers.RoamingSettings -{ - /// - /// An IObjectStorageHelper implementation using open extensions on the Graph User for storing key/value pairs. - /// - public class UserExtensionDataStore : BaseRoamingSettingsDataStore - { - /// - /// Retrieve the value from Graph User extensions and cast the response to the provided type. - /// - /// The type to cast the return result to. - /// The id of the user. - /// The id of the user extension. - /// The key for the desired value. - /// The value from the data store. - public static async Task Get(string userId, string extensionId, string key) - { - return (T)await Get(userId, extensionId, key); - } - - /// - /// Retrieve the value from Graph User extensions by extensionId, userId, and key. - /// - /// The id of the user. - /// The id of the user extension. - /// The key for the desired value. - /// The value from the data store. - public static async Task Get(string userId, string extensionId, string key) - { - var userExtension = await GetExtensionForUser(userId, extensionId); - return userExtension.AdditionalData[key]; - } - - /// - /// Set a value by key in a Graph User's extension. - /// - /// The id of the user. - /// The id of the user extension. - /// The key for the target value. - /// The value to set. - /// A task upon completion. - public static async Task Set(string userId, string extensionId, string key, object value) - { - await UserExtensionsDataSource.SetValue(userId, extensionId, key, value); - } - - /// - /// Creates a new roaming settings extension on a Graph User. - /// - /// The id of the user. - /// The id of the user extension. - /// The newly created user extension. - public static async Task Create(string userId, string extensionId) - { - var userExtension = await UserExtensionsDataSource.CreateExtension(userId, extensionId); - return userExtension; - } - - /// - /// Deletes an extension by id on a Graph User. - /// - /// The id of the user. - /// The id of the user extension. - /// A task upon completion. - public static async Task Delete(string userId, string extensionId) - { - await UserExtensionsDataSource.DeleteExtension(userId, extensionId); - } - - /// - /// Retrieves a user extension. - /// - /// The id of the user. - /// The id of the user extension. - /// The target extension. - public static async Task GetExtensionForUser(string userId, string extensionId) - { - var userExtension = await UserExtensionsDataSource.GetExtension(userId, extensionId); - return userExtension; - } - - private static readonly IList ReservedKeys = new List { "responseHeaders", "statusCode", "@odata.context" }; - - /// - /// Initializes a new instance of the class. - /// - public UserExtensionDataStore(string userId, string extensionId, IObjectSerializer objectSerializer, bool autoSync = true) - : base(userId, extensionId, objectSerializer, autoSync) - { - } - - /// - /// Creates a new roaming settings extension on the Graph User. - /// - /// The newly created Extension object. - public override async Task Create() - { - await Create(UserId, Id); - } - - /// - /// Deletes the roamingSettings extension from the Graph User. - /// - /// A void task. - public override async Task Delete() - { - // Delete the cache - Cache.Clear(); - - // Delete the remote. - await Delete(UserId, Id); - } - - /// - /// Update the remote extension to match the local cache and retrieve any new keys. Any existing remote values are replaced. - /// - /// The freshly synced user extension. - public override async Task Sync() - { - try - { - IDictionary remoteData = null; - - try - { - // Get the remote - Extension extension = await GetExtensionForUser(UserId, Id); - remoteData = extension.AdditionalData; - } - catch - { - } - - if (Cache != null) - { - // Send updates for all local values, overwriting the remote. - foreach (string key in Cache.Keys.ToList()) - { - if (ReservedKeys.Contains(key)) - { - continue; - } - - if (remoteData == null || !remoteData.ContainsKey(key) || !EqualityComparer.Default.Equals(remoteData[key], Cache[key])) - { - Save(key, Cache[key]); - } - } - } - - if (remoteData != null) - { - // Update local cache with additions from remote - foreach (string key in remoteData.Keys.ToList()) - { - if (!Cache.ContainsKey(key)) - { - Cache.Add(key, remoteData[key]); - } - } - } - - SyncCompleted?.Invoke(this, new EventArgs()); - } - catch - { - SyncFailed?.Invoke(this, new EventArgs()); - } - } - - /// - public override Task FileExistsAsync(string filePath) - { - throw new NotImplementedException(); - } - - /// - public override Task ReadFileAsync(string filePath, T @default = default) - { - throw new NotImplementedException(); - } - - /// - public override Task SaveFileAsync(string filePath, T value) - { - throw new NotImplementedException(); - } - } -} \ No newline at end of file diff --git a/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/UserExtensionsDataSource.cs b/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/UserExtensionsDataSource.cs deleted file mode 100644 index 32b5d38..0000000 --- a/CommunityToolkit.Graph.Uwp/Helpers/RoamingSettings/UserExtensionsDataSource.cs +++ /dev/null @@ -1,204 +0,0 @@ -// 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.Net.Http; -using System.Threading.Tasks; -using CommunityToolkit.Authentication; -using CommunityToolkit.Graph.Extensions; -using Microsoft.Graph; - -namespace CommunityToolkit.Uwp.Graph.Helpers.RoamingSettings -{ - /// - /// Manages Graph interaction with open extensions on the user. - /// - internal static class UserExtensionsDataSource - { - private static GraphServiceClient Graph => ProviderManager.Instance.GlobalProvider?.GetClient(); - - /// - /// Retrieve an extension object for a user. - /// - /// The user to access. - /// The extension to retrieve. - /// The extension result. - public static async Task GetExtension(string userId, string extensionId) - { - if (string.IsNullOrWhiteSpace(extensionId)) - { - throw new ArgumentNullException(nameof(extensionId)); - } - - if (string.IsNullOrWhiteSpace(userId)) - { - throw new ArgumentNullException(nameof(userId)); - } - - var extension = await Graph.Users[userId].Extensions[extensionId].Request().GetAsync(); - return extension; - } - - /// - /// Get all extension objects for a user. - /// - /// The user to access. - /// All extension results. - public static async Task> GetAllExtensions(string userId) - { - if (string.IsNullOrWhiteSpace(userId)) - { - throw new ArgumentNullException(nameof(userId)); - } - - var extensions = await Graph.Users[userId].Extensions.Request().GetAsync(); - return extensions; - } - - /// - /// Create a new extension object on a user. - /// - /// The user to access. - /// The id of the new extension. - /// The newly created extension. - public static async Task CreateExtension(string userId, string extensionId) - { - if (string.IsNullOrWhiteSpace(extensionId)) - { - throw new ArgumentNullException(nameof(extensionId)); - } - - if (string.IsNullOrWhiteSpace(userId)) - { - throw new ArgumentNullException(nameof(userId)); - } - - try - { - // Try to see if the extension already exists. - return await GetExtension(userId, extensionId); - } - catch - { - } - - string requestUrl = Graph.Users[userId].Extensions.Request().RequestUrl; - - string json = "{" + - "\"@odata.type\": \"microsoft.graph.openTypeExtension\"," + - "\"extensionName\": \"" + extensionId + "\"," + - "}"; - - HttpRequestMessage hrm = new HttpRequestMessage(HttpMethod.Post, requestUrl); - hrm.Content = new StringContent(json, System.Text.Encoding.UTF8, "application/json"); - await Graph.AuthenticationProvider.AuthenticateRequestAsync(hrm); - HttpResponseMessage response = await Graph.HttpProvider.SendAsync(hrm); - if (response.IsSuccessStatusCode) - { - // Deserialize into Extension object. - var content = await response.Content.ReadAsStringAsync(); - var extension = Graph.HttpProvider.Serializer.DeserializeObject(content); - return extension; - } - - return null; - } - - /// - /// Delete a user extension by id. - /// - /// The user to access. - /// The id of the extension to delete. - /// A task. - public static async Task DeleteExtension(string userId, string extensionId) - { - if (string.IsNullOrWhiteSpace(extensionId)) - { - throw new ArgumentNullException(nameof(extensionId)); - } - - if (string.IsNullOrWhiteSpace(userId)) - { - throw new ArgumentNullException(nameof(userId)); - } - - try - { - await GetExtension(userId, extensionId); - } - catch - { - // If we can't retrieve the extension, it must not exist. - return; - } - - await Graph.Users[userId].Extensions[extensionId].Request().DeleteAsync(); - } - - /// - /// Get a value from an extension by key. - /// - /// The type of object to return. - /// The target extension. - /// The key for the desired value. - /// The value for the provided key. - public static T GetValue(this Extension extension, string key) - { - return (T)GetValue(extension, key); - } - - /// - /// Get a value from a user extension by key. - /// - /// The target extension. - /// The key for the desired value. - /// The value for the provided key. - public static object GetValue(this Extension extension, string key) - { - if (string.IsNullOrWhiteSpace(key)) - { - throw new ArgumentNullException(nameof(key)); - } - - if (extension.AdditionalData.ContainsKey(key)) - { - return extension.AdditionalData[key]; - } - - return null; - } - - /// - /// Sets a user extension value at the specified key. - /// - /// The user to access. - /// The id of the target extension. - /// The key. - /// The value to set. - /// A task. - public static async Task SetValue(string userId, string extensionId, string key, object value) - { - if (string.IsNullOrWhiteSpace(userId)) - { - throw new ArgumentNullException(nameof(userId)); - } - - if (string.IsNullOrWhiteSpace(extensionId)) - { - throw new ArgumentNullException(nameof(extensionId)); - } - - if (string.IsNullOrWhiteSpace(key)) - { - throw new ArgumentNullException(nameof(key)); - } - - var extensionToUpdate = (Extension)Activator.CreateInstance(typeof(Extension), true); - extensionToUpdate.AdditionalData = new Dictionary() { { key, value } }; - - await Graph.Users[userId].Extensions[extensionId].Request().UpdateAsync(extensionToUpdate); - } - } -} \ No newline at end of file diff --git a/CommunityToolkit.Graph.Uwp/Properties/AssemblyInfo.cs b/CommunityToolkit.Graph.Uwp/Properties/AssemblyInfo.cs deleted file mode 100644 index c244792..0000000 --- a/CommunityToolkit.Graph.Uwp/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,11 +0,0 @@ -// 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.Resources; -using System.Runtime.CompilerServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: NeutralResourcesLanguage("en-US")] \ No newline at end of file diff --git a/CommunityToolkit.Graph.Uwp/Properties/CommunityToolkit.Uwp.Graph.Controls.rd.xml b/CommunityToolkit.Graph.Uwp/Properties/CommunityToolkit.Uwp.Graph.Controls.rd.xml deleted file mode 100644 index 419fe19..0000000 --- a/CommunityToolkit.Graph.Uwp/Properties/CommunityToolkit.Uwp.Graph.Controls.rd.xml +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/CommunityToolkit.Graph.Uwp/Themes/Generic.xaml b/CommunityToolkit.Graph.Uwp/Themes/Generic.xaml deleted file mode 100644 index 93e8a92..0000000 --- a/CommunityToolkit.Graph.Uwp/Themes/Generic.xaml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/CommunityToolkit.Graph.Uwp/VisualStudioToolsManifest.xml b/CommunityToolkit.Graph.Uwp/VisualStudioToolsManifest.xml deleted file mode 100644 index 1232610..0000000 --- a/CommunityToolkit.Graph.Uwp/VisualStudioToolsManifest.xml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/CommunityToolkit.Graph/CommunityToolkit.Graph.csproj b/CommunityToolkit.Graph/CommunityToolkit.Graph.csproj index 8d501e3..7d3ef51 100644 --- a/CommunityToolkit.Graph/CommunityToolkit.Graph.csproj +++ b/CommunityToolkit.Graph/CommunityToolkit.Graph.csproj @@ -6,7 +6,6 @@ Windows Community Toolkit .NET Standard Graph Services This package includes .NET Standard code helpers such as: - - GraphExtensions: Helpers for common tasks related to the Microsoft Graph used by the Microsoft.Toolkit.Graph.Controls. - ProviderExtensions: Extension on IProvider for accessing a pre-configured GraphServiceClient instance. Windows Community Toolkit Graph Provider Extensions diff --git a/CommunityToolkit.Graph/Extensions/GraphExtensions.People.cs b/CommunityToolkit.Graph/Extensions/GraphExtensions.People.cs deleted file mode 100644 index dccc79f..0000000 --- a/CommunityToolkit.Graph/Extensions/GraphExtensions.People.cs +++ /dev/null @@ -1,40 +0,0 @@ -// 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.Threading.Tasks; -using Microsoft.Graph; - -namespace CommunityToolkit.Graph.Extensions -{ - /// - /// People focused extension methods to the Graph SDK used by the controls and helpers. - /// - public static partial class GraphExtensions - { - /// - /// Shortcut to perform a person query. - /// - /// Instance of the . - /// User to search for. - /// collection of . - public static async Task FindPersonAsync(this GraphServiceClient graph, string query) - { - try - { - return await graph - .Me - .People - .Request() - .Search(query) - ////.WithScopes(new string[] { "people.read" }) - .GetAsync(); - } - catch - { - } - - return new UserPeopleCollectionPage(); - } - } -} diff --git a/CommunityToolkit.Graph/Extensions/GraphExtensions.Users.cs b/CommunityToolkit.Graph/Extensions/GraphExtensions.Users.cs deleted file mode 100644 index 7f0d381..0000000 --- a/CommunityToolkit.Graph/Extensions/GraphExtensions.Users.cs +++ /dev/null @@ -1,126 +0,0 @@ -// 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.IO; -using System.Threading.Tasks; -using Microsoft.Graph; - -namespace CommunityToolkit.Graph.Extensions -{ - /// - /// User focused extension methods to the Graph SDK used by the controls and helpers. - /// - public static partial class GraphExtensions - { - /// - /// Retrieve the curernt user. - /// - /// Instance of the . - /// A representing the asynchronous operation. - public static async Task GetMeAsync(this GraphServiceClient graph) - { - try - { - return await graph.Me.Request().GetAsync(); - } - catch - { - } - - return null; - } - - /// - /// Retrieve a user by id. - /// - /// Instance of the . - /// The is of the user to retrieve. - /// A representing the asynchronous operation. - public static async Task GetUserAsync(this GraphServiceClient graph, string userId) - { - try - { - return await graph.Users[userId].Request().GetAsync(); - } - catch - { - } - - return null; - } - - /// - /// Shortcut to perform a user query. - /// - /// Instance of the . - /// User to search for. - /// collection of . - public static async Task FindUserAsync(this GraphServiceClient graph, string query) - { - try - { - return await graph - .Users - .Request() - .Filter($"startswith(displayName, '{query}') or startswith(givenName, '{query}') or startswith(surname, '{query}') or startswith(mail, '{query}') or startswith(userPrincipalName, '{query}')") - ////.WithScopes(new string[] { "user.readbasic.all" }) - .GetAsync(); - } - catch - { - } - - return new GraphServiceUsersCollectionPage(); - } - - /// - /// Helper to get the photo of a particular user. - /// - /// Instance of the . - /// UserID. - /// Stream with user photo or null. - public static async Task GetUserPhoto(this GraphServiceClient graph, string userId) - { - try - { - return await graph - .Users[userId] - .Photo - .Content - .Request() - ////.WithScopes(new string[] { "user.readbasic.all" }) - .GetAsync(); - } - catch - { - } - - return null; - } - - /// - /// Get the photo of the current user. - /// - /// Instance of the . - /// Stream with user photo or null. - public static async Task GetMyPhotoAsync(this GraphServiceClient graph) - { - try - { - return await graph - .Me - .Photo - .Content - .Request() - ////.WithScopes(new string[] { "user.read" }) - .GetAsync(); - } - catch - { - } - - return null; - } - } -} diff --git a/CommunityToolkit.Graph/Extensions/GraphExtensions.cs b/CommunityToolkit.Graph/Extensions/GraphExtensions.cs deleted file mode 100644 index 118dba6..0000000 --- a/CommunityToolkit.Graph/Extensions/GraphExtensions.cs +++ /dev/null @@ -1,63 +0,0 @@ -// 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.Graph; - -namespace CommunityToolkit.Graph.Extensions -{ - /// - /// Extension methods to the Graph SDK used by the controls and helpers. - /// - public static partial class GraphExtensions - { - /// - /// Simple method to convert a to a with basic common properties like , , , , and intact. - /// - /// instance to convert. - /// A new basic representation of that user. - public static Person ToPerson(this User user) - { - return new Person() - { - // Primary Id - Id = user.Id, - UserPrincipalName = user.UserPrincipalName, - - // Standard User Info - DisplayName = user.DisplayName, - ScoredEmailAddresses = new ScoredEmailAddress[] - { - new ScoredEmailAddress() - { - Address = user.Mail ?? user.UserPrincipalName, - }, - }, - GivenName = user.GivenName, - Surname = user.Surname, - - // Company Information - CompanyName = user.CompanyName, - Department = user.Department, - JobTitle = user.JobTitle, - OfficeLocation = user.OfficeLocation, - }; - } - - /// - /// Extension to provider Searching on OData Requests. - /// - /// type. - /// Request chain. - /// Query to add for searching in QueryOptions. - /// Same type. - public static T Search(this T request, string query) - where T : IBaseRequest - { - // Need quotes around query for e-mail searches: https://docs.microsoft.com/en-us/graph/people-example#perform-a-fuzzy-search - request.QueryOptions?.Add(new QueryOption("$search", '"' + query + '"')); - - return request; - } - } -} diff --git a/SampleTest/App.xaml b/SampleTest/App.xaml deleted file mode 100644 index 13f775b..0000000 --- a/SampleTest/App.xaml +++ /dev/null @@ -1,4 +0,0 @@ - - diff --git a/SampleTest/App.xaml.cs b/SampleTest/App.xaml.cs deleted file mode 100644 index b12e662..0000000 --- a/SampleTest/App.xaml.cs +++ /dev/null @@ -1,146 +0,0 @@ -// 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 CommunityToolkit.Authentication; -using System; -using Windows.ApplicationModel; -using Windows.ApplicationModel.Activation; -using Windows.UI.Xaml; -using Windows.UI.Xaml.Controls; -using Windows.UI.Xaml.Navigation; - -namespace SampleTest -{ - /// - /// Provides application-specific behavior to supplement the default Application class. - /// - sealed partial class App : Application - { - /// - /// Initializes the singleton application object. This is the first line of authored code - /// executed, and as such is the logical equivalent of main() or WinMain(). - /// - public App() - { - this.InitializeComponent(); - this.Suspending += OnSuspending; - } - - // Which provider should be used for authentication? - private readonly ProviderType _providerType = ProviderType.Mock; - - // List of available authentication providers. - private enum ProviderType - { - Mock, - Msal, - Windows - } - - /// - /// Initialize the global authentication provider. - /// - private async void InitializeGlobalProvider() - { - if (ProviderManager.Instance.GlobalProvider != null) - { - return; - } - - await Window.Current.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => - { - // Provider config - string clientId = "YOUR_CLIENT_ID_HERE"; - string[] scopes = { "User.Read", "User.ReadBasic.All", "People.Read", "Calendars.Read", "Mail.Read", "Group.Read.All", "ChannelMessage.Read.All" }; - bool autoSignIn = true; - - switch (_providerType) - { - // Mock provider - case ProviderType.Mock: - ProviderManager.Instance.GlobalProvider = new MockProvider(signedIn: autoSignIn); - break; - - // Msal provider - case ProviderType.Msal: - ProviderManager.Instance.GlobalProvider = new MsalProvider(clientId: clientId, scopes: scopes, autoSignIn: autoSignIn); - break; - - // Windows provider - case ProviderType.Windows: - var webAccountProviderConfig = new WebAccountProviderConfig(WebAccountProviderType.Msa, clientId); - ProviderManager.Instance.GlobalProvider = new WindowsProvider(scopes, webAccountProviderConfig: webAccountProviderConfig, autoSignIn: autoSignIn); - break; - } - }); - } - - /// - /// Invoked when the application is launched normally by the end user. Other entry points - /// will be used such as when the application is launched to open a specific file. - /// - /// Details about the launch request and process. - protected override void OnLaunched(LaunchActivatedEventArgs e) - { - Frame rootFrame = Window.Current.Content as Frame; - - // Do not repeat app initialization when the Window already has content, - // just ensure that the window is active - if (rootFrame == null) - { - // Create a Frame to act as the navigation context and navigate to the first page - rootFrame = new Frame(); - - rootFrame.NavigationFailed += OnNavigationFailed; - - if (e.PreviousExecutionState == ApplicationExecutionState.Terminated) - { - //TODO: Load state from previously suspended application - } - - // Place the frame in the current Window - Window.Current.Content = rootFrame; - } - - if (e.PrelaunchActivated == false) - { - if (rootFrame.Content == null) - { - // When the navigation stack isn't restored navigate to the first page, - // configuring the new page by passing required information as a navigation - // parameter - rootFrame.Navigate(typeof(MainPage), e.Arguments); - } - // Ensure the current window is active - Window.Current.Activate(); - - InitializeGlobalProvider(); - } - } - - /// - /// Invoked when Navigation to a certain page fails - /// - /// The Frame which failed navigation - /// Details about the navigation failure - void OnNavigationFailed(object sender, NavigationFailedEventArgs e) - { - throw new Exception("Failed to load Page " + e.SourcePageType.FullName); - } - - /// - /// Invoked when application execution is being suspended. Application state is saved - /// without knowing whether the application will be terminated or resumed with the contents - /// of memory still intact. - /// - /// The source of the suspend request. - /// Details about the suspend request. - private void OnSuspending(object sender, SuspendingEventArgs e) - { - var deferral = e.SuspendingOperation.GetDeferral(); - //TODO: Save application state and stop any background activity - deferral.Complete(); - } - } -} diff --git a/SampleTest/Assets/FileIcon.png b/SampleTest/Assets/FileIcon.png deleted file mode 100644 index 0435822..0000000 Binary files a/SampleTest/Assets/FileIcon.png and /dev/null differ diff --git a/SampleTest/Assets/LockScreenLogo.scale-200.png b/SampleTest/Assets/LockScreenLogo.scale-200.png deleted file mode 100644 index 735f57a..0000000 Binary files a/SampleTest/Assets/LockScreenLogo.scale-200.png and /dev/null differ diff --git a/SampleTest/Assets/SplashScreen.scale-200.png b/SampleTest/Assets/SplashScreen.scale-200.png deleted file mode 100644 index 023e7f1..0000000 Binary files a/SampleTest/Assets/SplashScreen.scale-200.png and /dev/null differ diff --git a/SampleTest/Assets/Square150x150Logo.scale-200.png b/SampleTest/Assets/Square150x150Logo.scale-200.png deleted file mode 100644 index af49fec..0000000 Binary files a/SampleTest/Assets/Square150x150Logo.scale-200.png and /dev/null differ diff --git a/SampleTest/Assets/Square44x44Logo.scale-200.png b/SampleTest/Assets/Square44x44Logo.scale-200.png deleted file mode 100644 index ce342a2..0000000 Binary files a/SampleTest/Assets/Square44x44Logo.scale-200.png and /dev/null differ diff --git a/SampleTest/Assets/Square44x44Logo.targetsize-24_altform-unplated.png b/SampleTest/Assets/Square44x44Logo.targetsize-24_altform-unplated.png deleted file mode 100644 index f6c02ce..0000000 Binary files a/SampleTest/Assets/Square44x44Logo.targetsize-24_altform-unplated.png and /dev/null differ diff --git a/SampleTest/Assets/StoreLogo.png b/SampleTest/Assets/StoreLogo.png deleted file mode 100644 index 7385b56..0000000 Binary files a/SampleTest/Assets/StoreLogo.png and /dev/null differ diff --git a/SampleTest/Assets/Wide310x150Logo.scale-200.png b/SampleTest/Assets/Wide310x150Logo.scale-200.png deleted file mode 100644 index 288995b..0000000 Binary files a/SampleTest/Assets/Wide310x150Logo.scale-200.png and /dev/null differ diff --git a/SampleTest/MainPage.xaml b/SampleTest/MainPage.xaml deleted file mode 100644 index 76dcd4a..0000000 --- a/SampleTest/MainPage.xaml +++ /dev/null @@ -1,309 +0,0 @@ - - - - - - - - - - - The `LoginButton` above allows your user and application to easily connect to the Microsoft Graph. They can then also easily logout from the drop-down menu. - - - - - - - - - - The `PeoplePicker` lets a logged in user easily search for familiar people they interact with or contacts. Great for emails or messages. - - - - Picked People: - - - - - - - - - - - - - - - - - - The `GraphPresenter` is a unique control in the library which makes it easier for a developer to make any graph call and configure a nice display template in XAML. This opens up a world of possibilities for many uses outside of any other control available within this library. You can see a few examples of what's possible below. - - - - - - - - - - - - - The following example shows the `Me.CalendarView` API. - - My Upcoming Calendar Events: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The following example shows the `Me.Messages` API for getting a user's inbox mail messages. - - My Messages: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - The following example shows the `Me.Planner.Tasks` API for getting a user's tasks. - - My Tasks: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Due - - - - - - - - - - - - - - - - - - - - - - - The following example shows the beta `Teams/id/Channels/id/messages` API for getting a list of messages (without replies) from a Channel in Teams. - - My Chat Messages: - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/SampleTest/MainPage.xaml.cs b/SampleTest/MainPage.xaml.cs deleted file mode 100644 index 248db96..0000000 --- a/SampleTest/MainPage.xaml.cs +++ /dev/null @@ -1,83 +0,0 @@ -// 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 CommunityToolkit.Authentication; -using CommunityToolkit.Graph.Extensions; -using Microsoft.Graph; -using Microsoft.Graph.Extensions; -using System; -using System.Text.RegularExpressions; -using Windows.UI.Xaml.Controls; - -namespace SampleTest -{ - /// - /// An empty page that can be used on its own or navigated to within a Frame. - /// - public sealed partial class MainPage : Page - { - // Workaround for https://github.com/microsoft/microsoft-ui-xaml/issues/2407 - public DateTime Today => DateTimeOffset.Now.Date.ToUniversalTime(); - - // Workaround for https://github.com/microsoft/microsoft-ui-xaml/issues/2407 - public DateTime ThreeDaysFromNow => Today.AddDays(3); - - public IBaseRequestBuilder CalendarViewBuilder; - public IBaseRequestBuilder MessagesBuilder; - public IBaseRequestBuilder PlannerTasksBuilder; - public IBaseRequestBuilder TeamsChannelMessagesBuilder; - - public MainPage() - { - this.InitializeComponent(); - - ProviderManager.Instance.ProviderUpdated += this.OnProviderUpdated; - } - - private void OnProviderUpdated(object sender, ProviderUpdatedEventArgs e) - { - if (e.Reason == ProviderManagerChangedState.ProviderStateChanged - && sender is ProviderManager pm - && pm.GlobalProvider.State == ProviderState.SignedIn) - { - var graphClient = ProviderManager.Instance.GlobalProvider.GetClient(); - - CalendarViewBuilder = graphClient.Me.CalendarView; - MessagesBuilder = graphClient.Me.Messages; - PlannerTasksBuilder = graphClient.Me.Planner.Tasks; - TeamsChannelMessagesBuilder = graphClient.Teams["02bd9fd6-8f93-4758-87c3-1fb73740a315"].Channels["19:d0bba23c2fc8413991125a43a54cc30e@thread.skype"].Messages; - } - else - { - CalendarViewBuilder = null; - MessagesBuilder = null; - PlannerTasksBuilder = null; - TeamsChannelMessagesBuilder = null; - } - } - - public static string ToLocalTime(DateTimeTimeZone value) - { - // Workaround for https://github.com/microsoft/microsoft-ui-xaml/issues/2407 - return value.ToDateTimeOffset().LocalDateTime.ToString("g"); - } - - public static string ToLocalTime(DateTimeOffset? value) - { - // Workaround for https://github.com/microsoft/microsoft-ui-xaml/issues/2654 - return value?.LocalDateTime.ToString("g"); - } - - public static string RemoveWhitespace(string value) - { - // Workaround for https://github.com/microsoft/microsoft-ui-xaml/issues/2654 - return Regex.Replace(value, @"\t|\r|\n", " "); - } - - public static bool IsTaskCompleted(int? percentCompleted) - { - return percentCompleted == 100; - } - } -} diff --git a/SampleTest/Package.appxmanifest b/SampleTest/Package.appxmanifest deleted file mode 100644 index 2b919ae..0000000 --- a/SampleTest/Package.appxmanifest +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - - - SampleTest - Microsoft - Assets\StoreLogo.png - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/SampleTest/Properties/AssemblyInfo.cs b/SampleTest/Properties/AssemblyInfo.cs deleted file mode 100644 index 67a172e..0000000 --- a/SampleTest/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,31 +0,0 @@ -// 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.Reflection; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// General Information about an assembly is controlled through the following -// set of attributes. Change these attribute values to modify the information -// associated with an assembly. -[assembly: AssemblyTitle("SampleTest")] -[assembly: AssemblyDescription("")] -[assembly: AssemblyConfiguration("")] -[assembly: AssemblyCompany("")] -[assembly: AssemblyProduct("SampleTest")] -[assembly: AssemblyCopyright("Copyright © 2019")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] - -// Version information for an assembly consists of the following four values: -// -// Major Version -// Minor Version -// Build Number -// Revision -// -// You can specify all the values or you can default the Build and Revision Numbers -// by using the '*' as shown below: -// [assembly: AssemblyVersion("1.0.*")] -[assembly: ComVisible(false)] \ No newline at end of file diff --git a/SampleTest/Properties/Default.rd.xml b/SampleTest/Properties/Default.rd.xml deleted file mode 100644 index af00722..0000000 --- a/SampleTest/Properties/Default.rd.xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - - - - - - - - - \ No newline at end of file diff --git a/SampleTest/SampleTest.csproj b/SampleTest/SampleTest.csproj deleted file mode 100644 index eb8508b..0000000 --- a/SampleTest/SampleTest.csproj +++ /dev/null @@ -1,258 +0,0 @@ - - - - - Debug - x86 - {26F5807A-25B5-4E09-8C72-1749C4C59591} - AppContainerExe - Properties - SampleTest - SampleTest - en-US - UAP - 10.0.19041.0 - 10.0.17763.0 - 14 - 512 - {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} - true - false - - - true - bin\x86\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - x86 - false - prompt - true - - - bin\x86\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - x86 - false - prompt - true - true - - - true - bin\ARM\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - ARM - false - prompt - true - - - bin\ARM\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - ARM - false - prompt - true - true - - - true - bin\ARM64\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - ARM64 - false - prompt - true - true - - - bin\ARM64\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - ARM64 - false - prompt - true - true - - - true - bin\x64\Debug\ - DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP - ;2008 - full - x64 - false - prompt - true - - - bin\x64\Release\ - TRACE;NETFX_CORE;WINDOWS_UWP - true - ;2008 - pdbonly - x64 - false - prompt - true - true - - - PackageReference - - - - App.xaml - - - MainPage.xaml - - - - RoamingSettingsView.xaml - - - - - - Designer - - - - - - - - - - - - - - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - MSBuild:Compile - Designer - - - - - 3.31.0 - - - 6.2.12 - - - - - {ca4042d2-33a2-450b-8b9d-c286b9f3f3f4} - CommunityToolkit.Authentication.Msal - - - {b323a2e1-66ef-4037-95b7-2defa051b4b1} - CommunityToolkit.Authentication - - - {b2246169-0cd8-473c-aff6-172310e2c3f6} - CommunityToolkit.Graph - - - {2E4A708A-DF53-4863-B797-E14CDC6B90FA} - CommunityToolkit.Authentication.Uwp - - - {42252ee8-7e68-428f-972b-6d2dd3aa12cc} - CommunityToolkit.Graph.Uwp - - - - 14.0 - - - bin\x86\CI\ - TRACE;NETFX_CORE;WINDOWS_UWP;CODE_ANALYSIS - true - ;2008 - true - pdbonly - x86 - false - 7.3 - prompt - C:\code\Graph-Controls\Toolkit.ruleset - true - - - bin\ARM\CI\ - TRACE;NETFX_CORE;WINDOWS_UWP;CODE_ANALYSIS - true - ;2008 - true - pdbonly - ARM - false - 7.3 - prompt - C:\code\Graph-Controls\Toolkit.ruleset - true - - - bin\ARM64\CI\ - TRACE;NETFX_CORE;WINDOWS_UWP;CODE_ANALYSIS - true - ;2008 - true - pdbonly - ARM64 - false - 7.3 - prompt - C:\code\Graph-Controls\Toolkit.ruleset - true - - - bin\x64\CI\ - TRACE;NETFX_CORE;WINDOWS_UWP;CODE_ANALYSIS - true - ;2008 - true - pdbonly - x64 - false - 7.3 - prompt - C:\code\Graph-Controls\Toolkit.ruleset - true - - - - \ No newline at end of file diff --git a/SampleTest/Samples/RoamingSettings/RoamingSettingsView.xaml b/SampleTest/Samples/RoamingSettings/RoamingSettingsView.xaml deleted file mode 100644 index 398282c..0000000 --- a/SampleTest/Samples/RoamingSettings/RoamingSettingsView.xaml +++ /dev/null @@ -1,79 +0,0 @@ - - - - - - - - - - - -