Major refactor of PersonView with new sample page (#133)
* Major refactor of PersonView with new sample page * Added support for image decode pixel height/width in PersonView * Fixing the way Graph calls are made so we don't silence exceptions anymore.
This commit is contained in:
Родитель
6ec457e729
Коммит
f999c2bd40
|
@ -289,9 +289,14 @@ namespace CommunityToolkit.Graph.Uwp.Controls
|
|||
var provider = ProviderManager.Instance.GlobalProvider;
|
||||
if (provider != null)
|
||||
{
|
||||
// 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();
|
||||
try
|
||||
{
|
||||
UserDetails = await provider.GetClient().GetMeAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// TODO: Handle if UserDetails is null.
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,6 +6,7 @@ using System;
|
|||
using System.Collections;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using CommunityToolkit.Authentication;
|
||||
using CommunityToolkit.Graph.Extensions;
|
||||
using Microsoft.Graph;
|
||||
|
@ -68,49 +69,85 @@ namespace CommunityToolkit.Graph.Uwp.Controls
|
|||
|
||||
if (args.Reason == AutoSuggestionBoxTextChangeReason.UserInput)
|
||||
{
|
||||
var text = sender.Text;
|
||||
var list = SuggestedItemsSource as IList;
|
||||
|
||||
if (list != null)
|
||||
_typeTimer.Debounce(
|
||||
async () =>
|
||||
{
|
||||
_typeTimer.Debounce(
|
||||
async () =>
|
||||
var text = sender.Text;
|
||||
await UpdateResultsAsync(text);
|
||||
|
||||
// TODO: If we don't have Graph connection and just list of Person should we auto-filter here?
|
||||
}, TimeSpan.FromSeconds(0.3));
|
||||
}
|
||||
}
|
||||
|
||||
private async Task UpdateResultsAsync(string text)
|
||||
{
|
||||
var list = SuggestedItemsSource as IList;
|
||||
if (list == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var graph = ProviderManager.Instance.GlobalProvider.GetClient();
|
||||
if (graph == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// If empty, will clear out
|
||||
list.Clear();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(text))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
IGraphServiceUsersCollectionPage usersCollection = null;
|
||||
try
|
||||
{
|
||||
usersCollection = await graph.FindUserAsync(text);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// No users found.
|
||||
}
|
||||
|
||||
if (usersCollection != null)
|
||||
{
|
||||
foreach (var user in usersCollection.CurrentPage)
|
||||
{
|
||||
// Exclude people in suggested list that we already have picked
|
||||
if (!Items.Any(person => (person as Person)?.Id == user.Id))
|
||||
{
|
||||
var graph = ProviderManager.Instance.GlobalProvider.GetClient();
|
||||
if (graph != null)
|
||||
{
|
||||
// If empty, will clear out
|
||||
list.Clear();
|
||||
list.Add(user.ToPerson());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
IUserPeopleCollectionPage peopleCollection = null;
|
||||
try
|
||||
{
|
||||
peopleCollection = await graph.FindPersonAsync(text);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// No people found.
|
||||
}
|
||||
|
||||
// Grab ids of current suggestions
|
||||
var ids = list.Cast<object>().Select(person => (person as Person).Id);
|
||||
if (peopleCollection != null)
|
||||
{
|
||||
// Grab ids of current suggestions
|
||||
var ids = list.Cast<object>().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));
|
||||
foreach (var contact in peopleCollection.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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
// 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
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of visual representation to use for the person.
|
||||
/// </summary>
|
||||
public enum PersonAvatarType
|
||||
{
|
||||
/// <summary>
|
||||
/// Show a user's photo if available, otherwise show initials.
|
||||
/// </summary>
|
||||
Photo,
|
||||
|
||||
/// <summary>
|
||||
/// Show the user's initials only.
|
||||
/// </summary>
|
||||
Initials,
|
||||
}
|
||||
}
|
|
@ -135,5 +135,20 @@ namespace CommunityToolkit.Graph.Uwp.Controls
|
|||
/// </summary>
|
||||
public static readonly DependencyProperty PersonViewTypeProperty =
|
||||
DependencyProperty.Register(nameof(PersonViewType), typeof(PersonViewType), typeof(PersonView), new PropertyMetadata(PersonViewType.TwoLines, PersonViewTypePropertiesChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of visual to display in the image part of the template.
|
||||
/// </summary>
|
||||
public PersonAvatarType PersonAvatarType
|
||||
{
|
||||
get => (PersonAvatarType)GetValue(PersonAvatarTypeProperty);
|
||||
set => SetValue(PersonAvatarTypeProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="PersonAvatarType"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PersonAvatarTypeProperty =
|
||||
DependencyProperty.Register(nameof(PersonAvatarType), typeof(PersonAvatarType), typeof(PersonView), new PropertyMetadata(PersonAvatarType.Photo, PersonAvatarTypePropertiesChanged));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ using System.Threading.Tasks;
|
|||
using CommunityToolkit.Authentication;
|
||||
using CommunityToolkit.Graph.Extensions;
|
||||
using Microsoft.Graph;
|
||||
using Windows.System;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
|
@ -20,48 +21,19 @@ namespace CommunityToolkit.Graph.Uwp.Controls
|
|||
/// </summary>
|
||||
public partial class PersonView : Control
|
||||
{
|
||||
private const string PersonViewDefaultImageSourceResourceName = "PersonViewDefaultImageSource";
|
||||
|
||||
/// <summary>
|
||||
/// <see cref="PersonQuery"/> value used to retrieve the signed-in user's info.
|
||||
/// </summary>
|
||||
public const string PersonQueryMe = "me";
|
||||
|
||||
private string _photoId = null;
|
||||
private const string PersonViewDefaultImageSourceResourceName = "PersonViewDefaultImageSource";
|
||||
private const string PackageDefaultImageSource = "ms-appx:///CommunityToolkit.Graph.Uwp/Assets/person.png";
|
||||
|
||||
private string _defaultImageSource = "ms-appx:///Microsoft.Toolkit.Graph.Controls/Assets/person.png";
|
||||
|
||||
private BitmapImage _defaultImage;
|
||||
|
||||
private static async void PersonDetailsPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
private static 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;
|
||||
}
|
||||
}
|
||||
pv.UpdateVisual();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -78,20 +50,42 @@ namespace CommunityToolkit.Graph.Uwp.Controls
|
|||
{
|
||||
if (d is PersonView pv)
|
||||
{
|
||||
pv.IsLargeImage = pv.PersonViewType == PersonViewType.Avatar;
|
||||
pv.IsLargeImage = pv.PersonViewType is PersonViewType.TwoLines or PersonViewType.ThreeLines;
|
||||
|
||||
if (pv.IsLargeImage)
|
||||
{
|
||||
pv._imageDecodePixelHeight = 48;
|
||||
pv._imageDecodePixelWidth = 48;
|
||||
}
|
||||
else
|
||||
{
|
||||
pv._imageDecodePixelHeight = 24;
|
||||
pv._imageDecodePixelWidth = 24;
|
||||
}
|
||||
|
||||
pv.UpdateImageSize();
|
||||
}
|
||||
}
|
||||
|
||||
private static void PersonAvatarTypePropertiesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (d is PersonView pv)
|
||||
{
|
||||
pv.UpdateVisual();
|
||||
}
|
||||
}
|
||||
|
||||
private BitmapImage _defaultImage;
|
||||
private int _imageDecodePixelHeight;
|
||||
private int _imageDecodePixelWidth;
|
||||
private string _photoId = null;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PersonView"/> class.
|
||||
/// </summary>
|
||||
public PersonView()
|
||||
{
|
||||
this.DefaultStyleKey = typeof(PersonView);
|
||||
|
||||
_defaultImage = new BitmapImage(new Uri(_defaultImageSource));
|
||||
|
||||
ProviderManager.Instance.ProviderStateChanged += (sender, args) => LoadData();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
@ -99,13 +93,25 @@ namespace CommunityToolkit.Graph.Uwp.Controls
|
|||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
if (Resources.TryGetValue(PersonViewDefaultImageSourceResourceName, out object value) && value is string uri)
|
||||
if (Resources.TryGetValue(PersonViewDefaultImageSourceResourceName, out object value) && value is string uriString)
|
||||
{
|
||||
_defaultImageSource = uri;
|
||||
_defaultImage = new BitmapImage(new Uri(_defaultImageSource)); // TODO: Couldn't load image from app package, only remote or in our assembly?
|
||||
UserPhoto = _defaultImage;
|
||||
_defaultImage = new BitmapImage(new Uri(uriString));
|
||||
}
|
||||
else
|
||||
{
|
||||
_defaultImage = new BitmapImage(new Uri(PackageDefaultImageSource));
|
||||
}
|
||||
|
||||
ProviderManager.Instance.ProviderStateChanged -= OnProviderStateChanged;
|
||||
ProviderManager.Instance.ProviderStateChanged += OnProviderStateChanged;
|
||||
|
||||
VisualStateManager.GoToState(this, Enum.GetName(typeof(ProviderState), ProviderManager.Instance.State), true);
|
||||
LoadData();
|
||||
}
|
||||
|
||||
private void OnProviderStateChanged(object sender, ProviderStateChangedEventArgs e)
|
||||
{
|
||||
VisualStateManager.GoToState(this, Enum.GetName(typeof(ProviderState), e.NewState), true);
|
||||
LoadData();
|
||||
}
|
||||
|
||||
|
@ -113,116 +119,225 @@ namespace CommunityToolkit.Graph.Uwp.Controls
|
|||
{
|
||||
var provider = ProviderManager.Instance.GlobalProvider;
|
||||
|
||||
if (provider == null || provider.State != ProviderState.SignedIn)
|
||||
if (provider?.State == ProviderState.SignedIn)
|
||||
{
|
||||
// Set back to Default if not signed-in
|
||||
if (provider != null)
|
||||
{
|
||||
UserPhoto = _defaultImage;
|
||||
}
|
||||
|
||||
return;
|
||||
await TryLoadPersonDetailsAsync();
|
||||
UpdateVisual();
|
||||
}
|
||||
|
||||
if (PersonDetails != null && UserPhoto == null)
|
||||
else
|
||||
{
|
||||
await LoadImageAsync(PersonDetails);
|
||||
LoadDefaultImage();
|
||||
}
|
||||
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
|
||||
{
|
||||
}
|
||||
private async void UpdateVisual()
|
||||
{
|
||||
if (PersonAvatarType is PersonAvatarType.Initials)
|
||||
{
|
||||
var initialsLoaded = TryLoadInitials();
|
||||
if (initialsLoaded)
|
||||
{
|
||||
ClearUserPhoto();
|
||||
}
|
||||
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();
|
||||
LoadDefaultImage();
|
||||
}
|
||||
}
|
||||
else if (PersonDetails == null && !string.IsNullOrWhiteSpace(PersonQuery))
|
||||
else if (PersonDetails != null)
|
||||
{
|
||||
var people = await provider.GetClient().FindPersonAsync(PersonQuery);
|
||||
if (people != null && people.Count > 0)
|
||||
if (PersonDetails.Id != _photoId)
|
||||
{
|
||||
var person = people.FirstOrDefault();
|
||||
PersonDetails = person;
|
||||
await LoadImageAsync(person);
|
||||
LoadDefaultImage();
|
||||
|
||||
var photoLoaded = await TryLoadUserPhotoAsync();
|
||||
if (photoLoaded)
|
||||
{
|
||||
UpdateImageSize();
|
||||
}
|
||||
else
|
||||
{
|
||||
var initialsLoaded = TryLoadInitials();
|
||||
if (initialsLoaded)
|
||||
{
|
||||
ClearUserPhoto();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LoadDefaultImage();
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadImageAsync(Person person)
|
||||
private void LoadDefaultImage()
|
||||
{
|
||||
if (UserPhoto != _defaultImage)
|
||||
{
|
||||
UserPhoto = _defaultImage;
|
||||
UpdateImageSize();
|
||||
|
||||
_photoId = null;
|
||||
Initials = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateImageSize()
|
||||
{
|
||||
if (UserPhoto != null)
|
||||
{
|
||||
UserPhoto.DecodePixelHeight = _imageDecodePixelHeight;
|
||||
UserPhoto.DecodePixelWidth = _imageDecodePixelWidth;
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearUserPhoto()
|
||||
{
|
||||
UserPhoto = null;
|
||||
_photoId = null;
|
||||
}
|
||||
|
||||
private async Task<bool> TryLoadPersonDetailsAsync()
|
||||
{
|
||||
if (PersonDetails != null)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var provider = ProviderManager.Instance.GlobalProvider;
|
||||
if (provider?.State != ProviderState.SignedIn)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// TODO: Better guarding
|
||||
var graph = ProviderManager.Instance.GlobalProvider.GetBetaClient();
|
||||
if (!string.IsNullOrWhiteSpace(UserId))
|
||||
{
|
||||
var user = await provider.GetClient().GetUserAsync(UserId);
|
||||
PersonDetails = user.ToPerson();
|
||||
}
|
||||
else if (PersonQuery?.ToLowerInvariant() == PersonQueryMe)
|
||||
{
|
||||
var user = await provider.GetClient().GetMeAsync();
|
||||
PersonDetails = user.ToPerson();
|
||||
}
|
||||
else if (!string.IsNullOrWhiteSpace(PersonQuery))
|
||||
{
|
||||
var people = await provider.GetClient().FindPersonAsync(PersonQuery);
|
||||
if (people != null && people.Count > 0)
|
||||
{
|
||||
var person = people.FirstOrDefault();
|
||||
PersonDetails = person;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
return PersonDetails != null;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// If we can't load a photo, that's ok.
|
||||
// TODO: Log exception
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private async Task DecodeStreamAsync(Stream photoStream)
|
||||
private async Task<bool> TryLoadUserPhotoAsync()
|
||||
{
|
||||
var person = PersonDetails;
|
||||
if (person == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (PersonDetails.Id == _photoId && UserPhoto != null && UserPhoto != _defaultImage)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
var provider = ProviderManager.Instance.GlobalProvider;
|
||||
if (provider?.State != ProviderState.SignedIn)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Stream photoStream = null;
|
||||
|
||||
// TODO: Better guarding
|
||||
try
|
||||
{
|
||||
var graph = ProviderManager.Instance.GlobalProvider?.GetBetaClient();
|
||||
photoStream = await graph.GetUserPhoto(person.Id);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
}
|
||||
|
||||
if (photoStream != null)
|
||||
{
|
||||
var decodeResults = await TryDecodeStreamAsync(photoStream);
|
||||
if (decodeResults.Success)
|
||||
{
|
||||
UserPhoto = decodeResults.Image;
|
||||
_photoId = person.Id;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryLoadInitials()
|
||||
{
|
||||
if (!string.IsNullOrWhiteSpace(Initials))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (PersonDetails == null)
|
||||
{
|
||||
Initials = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
string initials = null;
|
||||
|
||||
if (PersonDetails?.GivenName?.Length > 0 && PersonDetails?.Surname?.Length > 0)
|
||||
{
|
||||
initials = string.Empty + PersonDetails.GivenName[0] + PersonDetails.Surname[0];
|
||||
}
|
||||
else if (PersonDetails?.DisplayName?.Length > 0)
|
||||
{
|
||||
// Grab first two initials in name
|
||||
var nameParts = PersonDetails.DisplayName.ToUpper().Split(' ').Select(i => i.First());
|
||||
initials = string.Join(string.Empty, nameParts.Where(i => char.IsLetter(i)).Take(2));
|
||||
}
|
||||
|
||||
Initials = initials;
|
||||
|
||||
return Initials != null;
|
||||
}
|
||||
|
||||
private async Task<(bool Success, BitmapImage Image)> TryDecodeStreamAsync(Stream photoStream)
|
||||
{
|
||||
if (photoStream != null)
|
||||
{
|
||||
using (var ras = photoStream.AsRandomAccessStream())
|
||||
try
|
||||
{
|
||||
using var ras = photoStream.AsRandomAccessStream();
|
||||
var bitmap = new BitmapImage();
|
||||
await bitmap.SetSourceAsync(ras);
|
||||
UserPhoto = bitmap;
|
||||
|
||||
return (true, bitmap);
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
return (false, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,30 +64,76 @@
|
|||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<controls:SwitchPresenter
|
||||
Grid.Column="1"
|
||||
Value="{Binding PersonViewType, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource ObjectToStringConverter}}"
|
||||
VerticalAlignment="Center">
|
||||
<!-- One line -->
|
||||
<controls:Case Value="OneLine">
|
||||
<TextBlock Margin="6,-2,2,0"
|
||||
FontWeight="SemiBold"
|
||||
Text="{Binding PersonDetails.DisplayName, RelativeSource={RelativeSource TemplatedParent}}" />
|
||||
</controls:Case>
|
||||
<Grid Grid.Column="1">
|
||||
<Grid Name="LoadingContent" Visibility="Collapsed"></Grid>
|
||||
|
||||
<!-- Two lines -->
|
||||
<controls:Case Value="TwoLines">
|
||||
<StackPanel Margin="6,-2,2,0" Spacing="2">
|
||||
<TextBlock
|
||||
FontWeight="SemiBold"
|
||||
Text="{Binding PersonDetails.DisplayName, RelativeSource={RelativeSource TemplatedParent}}"/>
|
||||
<TextBlock
|
||||
FontSize="12"
|
||||
Text="{Binding PersonDetails.ScoredEmailAddresses[0].Address, RelativeSource={RelativeSource TemplatedParent}}" />
|
||||
</StackPanel>
|
||||
</controls:Case>
|
||||
</controls:SwitchPresenter>
|
||||
<Grid Name="SignedInContent" Visibility="Collapsed">
|
||||
<controls:SwitchPresenter
|
||||
Value="{Binding PersonViewType, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource ObjectToStringConverter}}"
|
||||
VerticalAlignment="Center">
|
||||
<!-- Avatar -->
|
||||
<controls:Case Value="Avatar" IsDefault="True" />
|
||||
|
||||
<!-- One line -->
|
||||
<controls:Case Value="OneLine">
|
||||
<TextBlock Margin="6,-2,2,0"
|
||||
FontWeight="SemiBold"
|
||||
Text="{Binding PersonDetails.DisplayName, RelativeSource={RelativeSource TemplatedParent}}" />
|
||||
</controls:Case>
|
||||
|
||||
<!-- Two lines -->
|
||||
<controls:Case Value="TwoLines">
|
||||
<StackPanel Margin="6,-2,2,0" Spacing="2">
|
||||
<TextBlock
|
||||
FontWeight="SemiBold"
|
||||
Text="{Binding PersonDetails.DisplayName, RelativeSource={RelativeSource TemplatedParent}}"/>
|
||||
<TextBlock
|
||||
FontSize="12"
|
||||
Text="{Binding PersonDetails.ScoredEmailAddresses[0].Address, RelativeSource={RelativeSource TemplatedParent}}" />
|
||||
</StackPanel>
|
||||
</controls:Case>
|
||||
|
||||
<!-- Three lines-->
|
||||
<controls:Case Value="ThreeLines">
|
||||
<StackPanel Margin="6,-2,2,0" Spacing="2" VerticalAlignment="Center">
|
||||
<TextBlock
|
||||
FontWeight="SemiBold"
|
||||
Text="{Binding PersonDetails.DisplayName, RelativeSource={RelativeSource TemplatedParent}}"/>
|
||||
<TextBlock
|
||||
FontSize="12"
|
||||
Text="{Binding PersonDetails.ScoredEmailAddresses[0].Address, RelativeSource={RelativeSource TemplatedParent}}" />
|
||||
<TextBlock
|
||||
FontSize="12"
|
||||
Text="{Binding PersonDetails.JobTitle, RelativeSource={RelativeSource TemplatedParent}}" />
|
||||
</StackPanel>
|
||||
</controls:Case>
|
||||
</controls:SwitchPresenter>
|
||||
</Grid>
|
||||
|
||||
<Grid Name="SignedOutContent" Visibility="Collapsed">
|
||||
<TextBlock>foobar</TextBlock>
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="ProviderStates">
|
||||
<VisualState x:Name="Loading">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="LoadingContent.Visibility" Value="Visible" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="SignedIn">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="SignedInContent.Visibility" Value="Visible" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="SignedOut">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="SignedOutContent.Visibility" Value="Visible" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
|
|
|
@ -9,19 +9,24 @@ namespace CommunityToolkit.Graph.Uwp.Controls
|
|||
/// </summary>
|
||||
public enum PersonViewType
|
||||
{
|
||||
/**
|
||||
* Render only the avatar
|
||||
*/
|
||||
/// <summary>
|
||||
/// Render only the avatar.
|
||||
/// </summary>
|
||||
Avatar = 0,
|
||||
|
||||
/**
|
||||
* Render the avatar and one line of text
|
||||
*/
|
||||
/// <summary>
|
||||
/// Render the avatar and one line of text.
|
||||
/// </summary>
|
||||
OneLine = 1,
|
||||
|
||||
/**
|
||||
* Render the avatar and two lines of text
|
||||
*/
|
||||
/// <summary>
|
||||
/// Render the avatar and two lines of text.
|
||||
/// </summary>
|
||||
TwoLines = 2,
|
||||
|
||||
/// <summary>
|
||||
/// Render the avatar and three lines of text.
|
||||
/// </summary>
|
||||
ThreeLines = 3,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,15 +20,7 @@ namespace CommunityToolkit.Graph.Extensions
|
|||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
public static async Task<User> GetMeAsync(this GraphServiceClient graph)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await graph.Me.Request().GetAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return null;
|
||||
return await graph.Me.Request().GetAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -39,15 +31,7 @@ namespace CommunityToolkit.Graph.Extensions
|
|||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
public static async Task<User> GetUserAsync(this GraphServiceClient graph, string userId)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await graph.Users[userId].Request().GetAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return null;
|
||||
return await graph.Users[userId].Request().GetAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -58,20 +42,12 @@ namespace CommunityToolkit.Graph.Extensions
|
|||
/// <returns><see cref="IGraphServiceUsersCollectionPage"/> collection of <see cref="User"/>.</returns>
|
||||
public static async Task<IGraphServiceUsersCollectionPage> 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();
|
||||
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();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -82,21 +58,13 @@ namespace CommunityToolkit.Graph.Extensions
|
|||
/// <returns>Stream with user photo or null.</returns>
|
||||
public static async Task<Stream> 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;
|
||||
return await graph
|
||||
.Users[userId]
|
||||
.Photo
|
||||
.Content
|
||||
.Request()
|
||||
////.WithScopes(new string[] { "user.readbasic.all" })
|
||||
.GetAsync();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -106,21 +74,13 @@ namespace CommunityToolkit.Graph.Extensions
|
|||
/// <returns>Stream with user photo or null.</returns>
|
||||
public static async Task<Stream> GetMyPhotoAsync(this GraphServiceClient graph)
|
||||
{
|
||||
try
|
||||
{
|
||||
return await graph
|
||||
.Me
|
||||
.Photo
|
||||
.Content
|
||||
.Request()
|
||||
////.WithScopes(new string[] { "user.read" })
|
||||
.GetAsync();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return null;
|
||||
return await graph
|
||||
.Me
|
||||
.Photo
|
||||
.Content
|
||||
.Request()
|
||||
////.WithScopes(new string[] { "user.read" })
|
||||
.GetAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,9 @@
|
|||
<Setter Property="Margin" Value="8,8,8,0" />
|
||||
</Style>
|
||||
</Pivot.ItemContainerStyle>
|
||||
<PivotItem Header="PersonView">
|
||||
<samples:PersonViewSample />
|
||||
</PivotItem>
|
||||
<PivotItem Header="RoamingSettings">
|
||||
<samples:RoamingSettingsView />
|
||||
</PivotItem>
|
||||
|
|
|
@ -123,6 +123,9 @@
|
|||
<DependentUpon>MainPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Samples\PersonView\PersonViewSample.xaml.cs">
|
||||
<DependentUpon>PersonViewSample.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Samples\RoamingSettings\RoamingSettingsView.xaml.cs">
|
||||
<DependentUpon>RoamingSettingsView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
@ -135,6 +138,7 @@
|
|||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Content Include="Assets\FileIcon.png" />
|
||||
<None Include="Package.StoreAssociation.xml" />
|
||||
<Content Include="Properties\Default.rd.xml" />
|
||||
<Content Include="Assets\LockScreenLogo.scale-200.png" />
|
||||
<Content Include="Assets\SplashScreen.scale-200.png" />
|
||||
|
@ -153,6 +157,10 @@
|
|||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Include="Samples\PersonView\PersonViewSample.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="Samples\RoamingSettings\RoamingSettingsView.xaml">
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
<SubType>Designer</SubType>
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
<Page
|
||||
x:Class="SampleTest.Samples.PersonViewSample"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:SampleTest.Samples"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:controls="using:CommunityToolkit.Graph.Uwp.Controls"
|
||||
mc:Ignorable="d"
|
||||
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
|
||||
|
||||
<StackPanel>
|
||||
<TextBlock Text="Avatar" />
|
||||
<controls:PersonView PersonQuery="me" PersonViewType="Avatar" />
|
||||
<TextBlock Text="OneLine" />
|
||||
<controls:PersonView PersonQuery="me" PersonViewType="OneLine" />
|
||||
<TextBlock Text="TwoLines" />
|
||||
<controls:PersonView PersonQuery="me" PersonViewType="TwoLines" />
|
||||
<TextBlock Text="ThreeLines" />
|
||||
<controls:PersonView PersonQuery="me" PersonViewType="ThreeLines" />
|
||||
<TextBlock Text="Avatar w/ Initials" />
|
||||
<controls:PersonView PersonQuery="me" PersonViewType="Avatar" PersonAvatarType="Initials" />
|
||||
<TextBlock Text="TwoLines w/ Initials" />
|
||||
<controls:PersonView PersonQuery="me" PersonViewType="TwoLines" PersonAvatarType="Initials" />
|
||||
</StackPanel>
|
||||
</Page>
|
|
@ -0,0 +1,16 @@
|
|||
// 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 Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace SampleTest.Samples
|
||||
{
|
||||
public sealed partial class PersonViewSample : Page
|
||||
{
|
||||
public PersonViewSample()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
Загрузка…
Ссылка в новой задаче