cleaned up solution
This commit is contained in:
Родитель
57750a8487
Коммит
26c3bf89b0
|
@ -1,33 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
using System;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the events for the <see cref="AadLogin"/> control.
|
||||
/// </summary>
|
||||
public partial class AadLogin : Button
|
||||
{
|
||||
/// <summary>
|
||||
/// Occurs when the user is logged in.
|
||||
/// </summary>
|
||||
public event EventHandler<SignInEventArgs> SignInCompleted;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the user is logged out.
|
||||
/// </summary>
|
||||
public event EventHandler SignOutCompleted;
|
||||
}
|
||||
}
|
|
@ -1,162 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
using System;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the properties for the <see cref="AadLogin"/> control.
|
||||
/// </summary>
|
||||
public partial class AadLogin : Button
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets required delegated permissions for the <see cref="AadLogin"/> control
|
||||
/// </summary>
|
||||
public static string[] RequiredDelegatedPermissions
|
||||
{
|
||||
get
|
||||
{
|
||||
return new string[] { "User.Read" };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="DefaultImage"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty DefaultImageProperty = DependencyProperty.Register(
|
||||
nameof(DefaultImage),
|
||||
typeof(BitmapImage),
|
||||
typeof(AadLogin),
|
||||
new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="View"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ViewProperty = DependencyProperty.Register(
|
||||
nameof(View),
|
||||
typeof(ViewType),
|
||||
typeof(AadLogin),
|
||||
new PropertyMetadata(ViewType.PictureOnly));
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="AllowSignInAsDifferentUser"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty AllowSignInAsDifferentUserProperty = DependencyProperty.Register(
|
||||
nameof(AllowSignInAsDifferentUser),
|
||||
typeof(bool),
|
||||
typeof(AadLogin),
|
||||
new PropertyMetadata(true));
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="SignInDefaultText"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty SignInDefaultTextProperty = DependencyProperty.Register(
|
||||
nameof(SignInDefaultText),
|
||||
typeof(string),
|
||||
typeof(AadLogin),
|
||||
new PropertyMetadata("Sign In"));
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="SignOutDefaultText"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty SignOutDefaultTextProperty = DependencyProperty.Register(
|
||||
nameof(SignOutDefaultText),
|
||||
typeof(string),
|
||||
typeof(AadLogin),
|
||||
new PropertyMetadata("Sign Out"));
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="SignInAnotherUserDefaultText"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty SignInAnotherUserDefaultTextProperty = DependencyProperty.Register(
|
||||
nameof(SignInAnotherUserDefaultText),
|
||||
typeof(string),
|
||||
typeof(AadLogin),
|
||||
new PropertyMetadata("Sign in with another account"));
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="CurrentUserId"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty CurrentUserIdProperty = DependencyProperty.Register(
|
||||
nameof(CurrentUserId),
|
||||
typeof(string),
|
||||
typeof(AadLogin),
|
||||
new PropertyMetadata(null));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default user photo
|
||||
/// </summary>
|
||||
public BitmapImage DefaultImage
|
||||
{
|
||||
get { return (BitmapImage)GetValue(DefaultImageProperty); }
|
||||
set { SetValue(DefaultImageProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating which view type will be presented, the default value is PictureOnly.
|
||||
/// </summary>
|
||||
public ViewType View
|
||||
{
|
||||
get { return (ViewType)GetValue(ViewProperty); }
|
||||
set { SetValue(ViewProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether AllowSignInAsDifferentUser menu button is enabled for logged in user.
|
||||
/// </summary>
|
||||
public bool AllowSignInAsDifferentUser
|
||||
{
|
||||
get { return (bool)GetValue(AllowSignInAsDifferentUserProperty); }
|
||||
set { SetValue(AllowSignInAsDifferentUserProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value for default sign-in text.
|
||||
/// </summary>
|
||||
public string SignInDefaultText
|
||||
{
|
||||
get { return (string)GetValue(SignInDefaultTextProperty); }
|
||||
set { SetValue(SignInDefaultTextProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value for default sign-out text.
|
||||
/// </summary>
|
||||
public string SignOutDefaultText
|
||||
{
|
||||
get { return (string)GetValue(SignOutDefaultTextProperty); }
|
||||
set { SetValue(SignOutDefaultTextProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value for default text of the Sign-in-with-another-account button.
|
||||
/// </summary>
|
||||
public string SignInAnotherUserDefaultText
|
||||
{
|
||||
get { return (string)GetValue(SignInAnotherUserDefaultTextProperty); }
|
||||
set { SetValue(SignInAnotherUserDefaultTextProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the unique identifier for current signed in user.
|
||||
/// </summary>
|
||||
public string CurrentUserId
|
||||
{
|
||||
get { return (string)GetValue(CurrentUserIdProperty); }
|
||||
private set { SetValue(CurrentUserIdProperty, value); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,144 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Threading.Tasks;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Automation;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
/// <summary>
|
||||
/// The AAD Login Control leverages MSAL libraries to support basic AAD sign-in processes for Microsoft Graph and beyond.
|
||||
/// </summary>
|
||||
[TemplatePart(Name = "RootGrid", Type = typeof(Grid))]
|
||||
[TemplatePart(Name = "ContentPresenter", Type = typeof(ContentPresenter))]
|
||||
public partial class AadLogin : Button
|
||||
{
|
||||
private AadAuthenticationManager _aadAuthenticationManager = AadAuthenticationManager.Instance;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="AadLogin"/> class.
|
||||
/// </summary>
|
||||
public AadLogin()
|
||||
{
|
||||
DefaultStyleKey = typeof(AadLogin);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override default OnApplyTemplate to capture child controls
|
||||
/// </summary>
|
||||
protected override void OnApplyTemplate()
|
||||
{
|
||||
ApplyTemplate();
|
||||
|
||||
AutomationProperties.SetName(this, SignInDefaultText);
|
||||
|
||||
Click += async (object sender, RoutedEventArgs e) =>
|
||||
{
|
||||
if (!_aadAuthenticationManager.IsAuthenticated)
|
||||
{
|
||||
Flyout = null;
|
||||
await SignInAsync();
|
||||
}
|
||||
else
|
||||
{
|
||||
Flyout = GenerateMenuItems();
|
||||
}
|
||||
};
|
||||
|
||||
_aadAuthenticationManager.PropertyChanged += (object sender, PropertyChangedEventArgs e) =>
|
||||
{
|
||||
if (e.PropertyName == nameof(_aadAuthenticationManager.CurrentUserId))
|
||||
{
|
||||
CurrentUserId = _aadAuthenticationManager.CurrentUserId;
|
||||
}
|
||||
};
|
||||
|
||||
if (_aadAuthenticationManager.IsAuthenticated)
|
||||
{
|
||||
CurrentUserId = _aadAuthenticationManager.CurrentUserId;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is used to prompt to login screen.
|
||||
/// </summary>
|
||||
/// <returns>True if sign in successfully, otherwise false</returns>
|
||||
public async Task<bool> SignInAsync()
|
||||
{
|
||||
if (await _aadAuthenticationManager.ConnectAsync())
|
||||
{
|
||||
AutomationProperties.SetName(this, string.Empty);
|
||||
|
||||
Flyout = GenerateMenuItems();
|
||||
|
||||
SignInCompleted?.Invoke(this, new SignInEventArgs()
|
||||
{
|
||||
GraphClient = await _aadAuthenticationManager.GetGraphServiceClientAsync()
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is used to sign out the currently signed on user
|
||||
/// </summary>
|
||||
public void SignOut()
|
||||
{
|
||||
_aadAuthenticationManager.SignOut();
|
||||
SignOutCompleted?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private MenuFlyout GenerateMenuItems()
|
||||
{
|
||||
MenuFlyout menuFlyout = new MenuFlyout();
|
||||
|
||||
if (AllowSignInAsDifferentUser)
|
||||
{
|
||||
MenuFlyoutItem signinanotherItem = new MenuFlyoutItem
|
||||
{
|
||||
Text = SignInAnotherUserDefaultText
|
||||
};
|
||||
AutomationProperties.SetName(signinanotherItem, SignInAnotherUserDefaultText);
|
||||
signinanotherItem.Click += async (object sender, RoutedEventArgs e) =>
|
||||
{
|
||||
if (await _aadAuthenticationManager.ConnectForAnotherUserAsync())
|
||||
{
|
||||
var graphClient = await _aadAuthenticationManager.GetGraphServiceClientAsync();
|
||||
|
||||
SignInCompleted?.Invoke(this, new SignInEventArgs()
|
||||
{
|
||||
GraphClient = graphClient
|
||||
});
|
||||
}
|
||||
};
|
||||
menuFlyout.Items.Add(signinanotherItem);
|
||||
}
|
||||
|
||||
MenuFlyoutItem signoutItem = new MenuFlyoutItem
|
||||
{
|
||||
Text = SignOutDefaultText
|
||||
};
|
||||
AutomationProperties.SetName(signoutItem, SignOutDefaultText);
|
||||
signoutItem.Click += (object sender, RoutedEventArgs e) => _aadAuthenticationManager.SignOut();
|
||||
menuFlyout.Items.Add(signoutItem);
|
||||
|
||||
return menuFlyout;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,87 +0,0 @@
|
|||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls.Graph">
|
||||
|
||||
<Style TargetType="controls:AadLogin">
|
||||
<Setter Property="Background" Value="{ThemeResource ButtonBackground}"/>
|
||||
<Setter Property="Foreground" Value="{ThemeResource ButtonForeground}"/>
|
||||
<Setter Property="BorderBrush" Value="{ThemeResource ButtonBorderBrush}"/>
|
||||
<Setter Property="BorderThickness" Value="{ThemeResource ButtonBorderThemeThickness}"/>
|
||||
<Setter Property="Padding" Value="8,4,8,4"/>
|
||||
<Setter Property="HorizontalAlignment" Value="Left"/>
|
||||
<Setter Property="VerticalAlignment" Value="Center"/>
|
||||
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}"/>
|
||||
<Setter Property="FontWeight" Value="Normal"/>
|
||||
<Setter Property="FontSize" Value="{ThemeResource ControlContentThemeFontSize}"/>
|
||||
<Setter Property="UseSystemFocusVisuals" Value="True"/>
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="controls:AadLogin">
|
||||
<Grid x:Name="RootGrid" Background="{TemplateBinding Background}">
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="CommonStates">
|
||||
<VisualState x:Name="Normal">
|
||||
<Storyboard>
|
||||
<PointerUpThemeAnimation Storyboard.TargetName="RootGrid"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="PointerOver">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundPointerOver}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushPointerOver}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundPointerOver}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<PointerUpThemeAnimation Storyboard.TargetName="RootGrid"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Pressed">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundPressed}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushPressed}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundPressed}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<PointerDownThemeAnimation Storyboard.TargetName="RootGrid"/>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Disabled">
|
||||
<Storyboard>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="RootGrid" Storyboard.TargetProperty="Background">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBackgroundDisabled}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="BorderBrush">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonBorderBrushDisabled}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
<ObjectAnimationUsingKeyFrames Storyboard.TargetName="ContentPresenter" Storyboard.TargetProperty="Foreground">
|
||||
<DiscreteObjectKeyFrame KeyTime="0" Value="{ThemeResource ButtonForegroundDisabled}"/>
|
||||
</ObjectAnimationUsingKeyFrames>
|
||||
</Storyboard>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
<ContentPresenter x:Name="ContentPresenter" AutomationProperties.AccessibilityView="Raw" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" ContentTemplate="{TemplateBinding ContentTemplate}" ContentTransitions="{TemplateBinding ContentTransitions}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}">
|
||||
<ContentPresenter.Content>
|
||||
<controls:ProfileCard
|
||||
DisplayMode="{TemplateBinding View}"
|
||||
DefaultImage="{TemplateBinding DefaultImage}"
|
||||
UserId="{TemplateBinding CurrentUserId}"
|
||||
LargeProfileTitleDefaultText="{TemplateBinding SignInDefaultText}"
|
||||
NormalMailDefaultText="{TemplateBinding SignInDefaultText}"/>
|
||||
</ContentPresenter.Content>
|
||||
</ContentPresenter>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
|
@ -1,34 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
using Microsoft.Graph;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
/// <summary>
|
||||
/// Arguments relating to a sign-in event of Aadlogin control
|
||||
/// </summary>
|
||||
public class SignInEventArgs
|
||||
{
|
||||
internal SignInEventArgs()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the graph service client with authorized token.
|
||||
/// </summary>
|
||||
public GraphServiceClient GraphClient
|
||||
{
|
||||
get; internal set;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 21.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 32 32" enable-background="new 0 0 32 32" xml:space="preserve">
|
||||
<g id="TEMPLATE" display="none">
|
||||
<g display="inline">
|
||||
<path fill="#D0D0D0" d="M32,0v32H0V0H32 M33-1h-1H0h-1v1v32v1h1h32h1v-1V0V-1L33-1z"/>
|
||||
</g>
|
||||
<path display="inline" opacity="0.1" fill="#FF1D25" d="M0,0v32h32V0H0z M30,30H2V2h28V30z"/>
|
||||
</g>
|
||||
<g id="ICONS">
|
||||
<polygon fill="#A6A6A6" points="2,26 2,9 16,9 19,6 30,6 30,26 "/>
|
||||
<polygon fill="#828282" points="19,6 16,9 19,12 30,12 30,6 "/>
|
||||
<linearGradient id="SVGID_1_" gradientUnits="userSpaceOnUse" x1="6.7687" y1="4.9986" x2="26.7085" y2="28.7619">
|
||||
<stop offset="0" style="stop-color:#000000;stop-opacity:0"/>
|
||||
<stop offset="0.8625" style="stop-color:#000000;stop-opacity:0.1725"/>
|
||||
<stop offset="1" style="stop-color:#000000;stop-opacity:0.2"/>
|
||||
</linearGradient>
|
||||
<polygon fill="url(#SVGID_1_)" points="2,26 2,9 16,9 19,6 30,6 30,26 "/>
|
||||
<linearGradient id="SVGID_2_" gradientUnits="userSpaceOnUse" x1="23.4439" y1="5.4264" x2="22.8394" y2="12.3359">
|
||||
<stop offset="0" style="stop-color:#828282;stop-opacity:0"/>
|
||||
<stop offset="0.4267" style="stop-color:#808080;stop-opacity:0.1067"/>
|
||||
<stop offset="0.5804" style="stop-color:#797979;stop-opacity:0.1451"/>
|
||||
<stop offset="0.6899" style="stop-color:#6E6E6E;stop-opacity:0.1725"/>
|
||||
<stop offset="0.7785" style="stop-color:#5D5D5D;stop-opacity:0.1946"/>
|
||||
<stop offset="0.8543" style="stop-color:#474747;stop-opacity:0.2136"/>
|
||||
<stop offset="0.9215" style="stop-color:#2B2B2B;stop-opacity:0.2304"/>
|
||||
<stop offset="0.9808" style="stop-color:#0C0C0C;stop-opacity:0.2452"/>
|
||||
<stop offset="1" style="stop-color:#000000;stop-opacity:0.25"/>
|
||||
</linearGradient>
|
||||
<polygon fill="url(#SVGID_2_)" points="19,6 16,9 19,12 30,12 30,6 "/>
|
||||
<polygon opacity="0.15" fill="#FFFFFF" points="30,12 30,12.5 18.7708,12.5 15.25,9 16,9 19.0208,12 "/>
|
||||
</g>
|
||||
</svg>
|
До Ширина: | Высота: | Размер: 2.1 KiB |
Двоичные данные
Microsoft.Toolkit.Uwp.UI.Controls/Graph/Assets/genericfile.png
Двоичные данные
Microsoft.Toolkit.Uwp.UI.Controls/Graph/Assets/genericfile.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 389 B |
Двоичные данные
Microsoft.Toolkit.Uwp.UI.Controls/Graph/Assets/person.png
Двоичные данные
Microsoft.Toolkit.Uwp.UI.Controls/Graph/Assets/person.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 5.1 KiB |
Двоичные данные
Microsoft.Toolkit.Uwp.UI.Controls/Graph/Assets/photo.png
Двоичные данные
Microsoft.Toolkit.Uwp.UI.Controls/Graph/Assets/photo.png
Двоичный файл не отображается.
До Ширина: | Высота: | Размер: 610 B |
|
@ -1,281 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Graph;
|
||||
using Microsoft.Identity.Client;
|
||||
using Microsoft.Toolkit.Services.MicrosoftGraph;
|
||||
using static Microsoft.Toolkit.Services.MicrosoftGraph.MicrosoftGraphEnums;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
/// <summary>
|
||||
/// Microsoft Graph authentication manager for Microsoft Toolkit Graph controls using Microsoft Authentication Library (MSAL)
|
||||
/// </summary>
|
||||
public sealed class AadAuthenticationManager : MicrosoftGraphService, INotifyPropertyChanged
|
||||
{
|
||||
private static PublicClientApplication _publicClientApp = null;
|
||||
private static AadAuthenticationManager _instance;
|
||||
|
||||
/// <summary>
|
||||
/// Gets public singleton property.
|
||||
/// </summary>
|
||||
public static new AadAuthenticationManager Instance => _instance ?? (_instance = new AadAuthenticationManager());
|
||||
|
||||
private AadAuthenticationManager()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets current application ID.
|
||||
/// </summary>
|
||||
public string ClientId
|
||||
{
|
||||
get
|
||||
{
|
||||
return AppClientId;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets current permission scopes.
|
||||
/// </summary>
|
||||
public string[] Scopes
|
||||
{
|
||||
get
|
||||
{
|
||||
return DelegatedPermissionScopes;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether authenticated.
|
||||
/// </summary>
|
||||
public bool IsAuthenticated
|
||||
{
|
||||
get
|
||||
{
|
||||
return _isAuthenticated;
|
||||
}
|
||||
|
||||
private set
|
||||
{
|
||||
if (value != _isAuthenticated)
|
||||
{
|
||||
_isAuthenticated = value;
|
||||
NotifyPropertyChanged(nameof(IsAuthenticated));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private bool _isAuthenticated = false;
|
||||
|
||||
/// <summary>
|
||||
/// Gets current user id.
|
||||
/// </summary>
|
||||
public string CurrentUserId
|
||||
{
|
||||
get
|
||||
{
|
||||
return _currentUserId;
|
||||
}
|
||||
|
||||
private set
|
||||
{
|
||||
if (value != _currentUserId)
|
||||
{
|
||||
_currentUserId = value;
|
||||
NotifyPropertyChanged(nameof(CurrentUserId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string _currentUserId;
|
||||
|
||||
/// <summary>
|
||||
/// Gets field to store the model of authentication
|
||||
/// V1 Only for Work or Scholar account
|
||||
/// V2 for MSA and Work or Scholar account
|
||||
/// </summary>
|
||||
public new AuthenticationModel AuthenticationModel
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.AuthenticationModel;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets store a reference to an instance of the underlying data provider.
|
||||
/// </summary>
|
||||
public new GraphServiceClient GraphProvider
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.GraphProvider;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets fields to store a MicrosoftGraphServiceMessages instance
|
||||
/// </summary>
|
||||
public new MicrosoftGraphUserService User
|
||||
{
|
||||
get
|
||||
{
|
||||
return base.User;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Property changed eventHandler for notification.
|
||||
/// </summary>
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Initialize for the <see cref="AadAuthenticationManager"/> class
|
||||
/// </summary>
|
||||
/// <param name="clientId">Application client ID for MSAL v2 endpoints</param>
|
||||
/// <param name="scopes">Permission scopes for MSAL v2 endpoints</param>
|
||||
public void Initialize(string clientId, params string[] scopes)
|
||||
{
|
||||
if (string.IsNullOrEmpty(clientId))
|
||||
{
|
||||
throw new ArgumentNullException(nameof(clientId));
|
||||
}
|
||||
|
||||
if (scopes.Length == 0)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(scopes));
|
||||
}
|
||||
|
||||
base.AuthenticationModel = AuthenticationModel.V2;
|
||||
|
||||
base.Initialize(clientId, ServicesToInitialize.UserProfile, scopes);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize Microsoft Graph.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Concrete type that inherits IMicrosoftGraphUserServicePhotos.</typeparam>
|
||||
/// <param name='appClientId'>Azure AD's App client id</param>
|
||||
/// <param name="servicesToInitialize">A combination of value to instanciate different services</param>
|
||||
/// <param name="delegatedPermissionScopes">Permission scopes for MSAL v2 endpoints</param>
|
||||
/// <param name="uiParent">UiParent instance - required for Android</param>
|
||||
/// <param name="redirectUri">Redirect Uri - required for Android</param>
|
||||
/// <returns>Success or failure.</returns>
|
||||
[Obsolete("This is not supported in this class.", true)]
|
||||
public new bool Initialize<T>(string appClientId, ServicesToInitialize servicesToInitialize = ServicesToInitialize.Message | ServicesToInitialize.UserProfile | ServicesToInitialize.Event, string[] delegatedPermissionScopes = null, UIParent uiParent = null, string redirectUri = null)
|
||||
where T : IMicrosoftGraphUserServicePhotos, new()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initialize Microsoft Graph.
|
||||
/// </summary>
|
||||
/// <param name='appClientId'>Azure AD's App client id</param>
|
||||
/// <param name="servicesToInitialize">A combination of value to instanciate different services</param>
|
||||
/// <param name="delegatedPermissionScopes">Permission scopes for MSAL v2 endpoints</param>
|
||||
/// <param name="uiParent">UiParent instance - required for Android</param>
|
||||
/// <param name="redirectUri">Redirect Uri - required for Android</param>
|
||||
/// <returns>Success or failure.</returns>
|
||||
[Obsolete("This is not supported in this class.", true)]
|
||||
public new bool Initialize(string appClientId, ServicesToInitialize servicesToInitialize = ServicesToInitialize.Message | ServicesToInitialize.UserProfile | ServicesToInitialize.Event, string[] delegatedPermissionScopes = null, UIParent uiParent = null, string redirectUri = null)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
internal async Task<bool> ConnectAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
IsAuthenticated = await LoginAsync();
|
||||
if (IsAuthenticated)
|
||||
{
|
||||
CurrentUserId = (await User.GetProfileAsync(new MicrosoftGraphUserFields[1] { MicrosoftGraphUserFields.Id })).Id;
|
||||
}
|
||||
}
|
||||
catch (MsalServiceException ex)
|
||||
{
|
||||
// Swallow error in case of authentication cancellation.
|
||||
if (ex.ErrorCode != "authentication_canceled"
|
||||
&& ex.ErrorCode != "access_denied")
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
return IsAuthenticated;
|
||||
}
|
||||
|
||||
internal Task<GraphServiceClient> GetGraphServiceClientAsync()
|
||||
{
|
||||
return Task.FromResult(GraphProvider);
|
||||
}
|
||||
|
||||
internal async void SignOut()
|
||||
{
|
||||
await Logout();
|
||||
CurrentUserId = string.Empty;
|
||||
IsAuthenticated = false;
|
||||
}
|
||||
|
||||
internal async Task<bool> ConnectForAnotherUserAsync()
|
||||
{
|
||||
if (!IsInitialized)
|
||||
{
|
||||
throw new InvalidOperationException("Microsoft Graph not initialized.");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
_publicClientApp = new PublicClientApplication(ClientId);
|
||||
AuthenticationResult result = await _publicClientApp.AcquireTokenAsync(Scopes);
|
||||
|
||||
var signedUser = result.User;
|
||||
|
||||
foreach (var user in _publicClientApp.Users)
|
||||
{
|
||||
if (user.Identifier != signedUser.Identifier)
|
||||
{
|
||||
_publicClientApp.Remove(user);
|
||||
}
|
||||
}
|
||||
|
||||
await LoginAsync();
|
||||
CurrentUserId = (await User.GetProfileAsync(new MicrosoftGraphUserFields[1] { MicrosoftGraphUserFields.Id })).Id;
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (MsalServiceException ex)
|
||||
{
|
||||
// Swallow error in case of authentication cancellation.
|
||||
if (ex.ErrorCode != "authentication_canceled"
|
||||
&& ex.ErrorCode != "access_denied")
|
||||
{
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
|
||||
{
|
||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,151 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Graph;
|
||||
using Microsoft.Toolkit.Uwp.UI.Extensions;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the events for the <see cref="PeoplePicker"/> control.
|
||||
/// </summary>
|
||||
public partial class PeoplePicker : Control
|
||||
{
|
||||
private static void AllowMultiplePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var control = d as PeoplePicker;
|
||||
if (!control.AllowMultiple)
|
||||
{
|
||||
control.Selections.Clear();
|
||||
control.RaiseSelectionChanged();
|
||||
control._searchBox.Text = string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearAndHideSearchResultListBox()
|
||||
{
|
||||
SearchResultList.Clear();
|
||||
_searchResultListBox.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private async void SearchBox_OnTextChanged(object sender, TextChangedEventArgs e)
|
||||
{
|
||||
var textboxSender = (TextBox)sender;
|
||||
string searchText = textboxSender.Text.Trim();
|
||||
if (string.IsNullOrWhiteSpace(searchText))
|
||||
{
|
||||
ClearAndHideSearchResultListBox();
|
||||
return;
|
||||
}
|
||||
|
||||
_loading.IsActive = true;
|
||||
|
||||
searchText = Regex.Replace(searchText, "[^0-9a-zA-Z .@]", string.Empty);
|
||||
int cursorPosition = textboxSender.SelectionStart;
|
||||
textboxSender.Text = searchText;
|
||||
textboxSender.SelectionStart = cursorPosition;
|
||||
|
||||
try
|
||||
{
|
||||
Task<GraphServiceClient> graphClient = AadAuthenticationManager.Instance.GetGraphServiceClientAsync();
|
||||
|
||||
var options = new List<QueryOption>
|
||||
{
|
||||
new QueryOption("$search", searchText)
|
||||
};
|
||||
IUserPeopleCollectionPage peopleList = await (await graphClient).Me.People.Request(options).GetAsync();
|
||||
|
||||
if (peopleList.Any())
|
||||
{
|
||||
List<Person> searchResult = peopleList.Where(
|
||||
u => !string.IsNullOrWhiteSpace(u.UserPrincipalName)).ToList();
|
||||
|
||||
// Remove all selected items
|
||||
foreach (Person selectedItem in Selections)
|
||||
{
|
||||
searchResult.RemoveAll(u => u.UserPrincipalName == selectedItem.UserPrincipalName);
|
||||
}
|
||||
|
||||
SearchResultList.Clear();
|
||||
var result = SearchResultLimit > 0
|
||||
? searchResult.Take(SearchResultLimit).ToList()
|
||||
: searchResult;
|
||||
foreach (var item in result)
|
||||
{
|
||||
SearchResultList.Add(item);
|
||||
}
|
||||
|
||||
_searchResultListBox.Visibility = Visibility.Visible;
|
||||
}
|
||||
else
|
||||
{
|
||||
ClearAndHideSearchResultListBox();
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
_loading.IsActive = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void SearchResultListBox_OnSelectionChanged(object sender, Windows.UI.Xaml.Controls.SelectionChangedEventArgs e)
|
||||
{
|
||||
if (!((sender as ListBox)?.SelectedItem is Person person))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!AllowMultiple && Selections.Any())
|
||||
{
|
||||
Selections.Clear();
|
||||
Selections.Add(person);
|
||||
}
|
||||
else
|
||||
{
|
||||
Selections.Add(person);
|
||||
}
|
||||
RaiseSelectionChanged();
|
||||
|
||||
_searchBox.Text = string.Empty;
|
||||
}
|
||||
|
||||
private void SelectionsListBox_Tapped(object sender, Windows.UI.Xaml.Input.TappedRoutedEventArgs e)
|
||||
{
|
||||
var elem = e.OriginalSource as FrameworkElement;
|
||||
|
||||
var removeButton = elem.FindAscendantByName("PersonRemoveButton");
|
||||
if (removeButton != null)
|
||||
{
|
||||
if (removeButton.Tag is Person item)
|
||||
{
|
||||
Selections.Remove(item);
|
||||
RaiseSelectionChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void RaiseSelectionChanged()
|
||||
{
|
||||
this.SelectionChanged?.Invoke(this, new PeopleSelectionChangedEventArgs(this.Selections));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,136 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Windows.Input;
|
||||
using Microsoft.Graph;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Defines the properties for the <see cref="PeoplePicker"/> control.
|
||||
/// </summary>
|
||||
public partial class PeoplePicker : Control
|
||||
{
|
||||
/// <summary>
|
||||
/// File is selected
|
||||
/// </summary>
|
||||
public event EventHandler<PeopleSelectionChangedEventArgs> SelectionChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Gets required delegated permissions for the <see cref="PeoplePicker"/> control
|
||||
/// </summary>
|
||||
public static string[] RequiredDelegatedPermissions
|
||||
{
|
||||
get
|
||||
{
|
||||
return new string[] { "User.Read", "User.ReadBasic.All" };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="AllowMultiple"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty AllowMultipleProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(AllowMultiple),
|
||||
typeof(bool),
|
||||
typeof(PeoplePicker),
|
||||
new PropertyMetadata(true, AllowMultiplePropertyChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="SearchResultLimit"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty SearchResultLimitProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(SearchResultLimit),
|
||||
typeof(int),
|
||||
typeof(PeoplePicker),
|
||||
null);
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="PlaceholderText"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PlaceholderTextProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(PlaceholderText),
|
||||
typeof(string),
|
||||
typeof(PeoplePicker),
|
||||
new PropertyMetadata("Enter keywords to search people"));
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="Selections"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty SelectionsProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(Selections),
|
||||
typeof(ObservableCollection<Person>),
|
||||
typeof(PeoplePicker),
|
||||
null);
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="SearchResultList"/> dependency property.
|
||||
/// </summary>
|
||||
internal static readonly DependencyProperty SearchResultListProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(SearchResultList),
|
||||
typeof(ObservableCollection<Person>),
|
||||
typeof(PeoplePicker),
|
||||
null);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether multiple people can be selected
|
||||
/// </summary>
|
||||
public bool AllowMultiple
|
||||
{
|
||||
get => (bool)GetValue(AllowMultipleProperty);
|
||||
set => SetValue(AllowMultipleProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the max person returned in the search results
|
||||
/// </summary>
|
||||
public int SearchResultLimit
|
||||
{
|
||||
get => (int)GetValue(SearchResultLimitProperty);
|
||||
set => SetValue(SearchResultLimitProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the text to be displayed when no user is selected
|
||||
/// </summary>
|
||||
public string PlaceholderText
|
||||
{
|
||||
get => (string)GetValue(PlaceholderTextProperty);
|
||||
set => SetValue(PlaceholderTextProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the selected person list.
|
||||
/// </summary>
|
||||
public ObservableCollection<Person> Selections
|
||||
{
|
||||
get => (ObservableCollection<Person>)GetValue(SelectionsProperty);
|
||||
set => SetValue(SelectionsProperty, value);
|
||||
}
|
||||
|
||||
internal ObservableCollection<Person> SearchResultList
|
||||
{
|
||||
get => (ObservableCollection<Person>)GetValue(SearchResultListProperty);
|
||||
set => SetValue(SearchResultListProperty, value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,86 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
using System.Collections.ObjectModel;
|
||||
using Microsoft.Graph;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
/// <summary>
|
||||
/// The PeoplePicker Control is a simple control that allows for selection of one or more users from an organizational AD.
|
||||
/// </summary>
|
||||
[TemplatePart(Name = GraphAccessTokenPartName, Type = typeof(TextBox))]
|
||||
[TemplatePart(Name = SearchBoxPartName, Type = typeof(TextBox))]
|
||||
[TemplatePart(Name = LoadingPartName, Type = typeof(ProgressRing))]
|
||||
[TemplatePart(Name = SearchResultListBoxPartName, Type = typeof(ListBox))]
|
||||
[TemplatePart(Name = SelectionsListBoxPartName, Type = typeof(ListBox))]
|
||||
[TemplatePart(Name = SelectionsCounterPartName, Type = typeof(TextBlock))]
|
||||
public partial class PeoplePicker : Control
|
||||
{
|
||||
private const string GraphAccessTokenPartName = "tbGraphAccessToken";
|
||||
private const string SearchBoxPartName = "SearchBox";
|
||||
private const string LoadingPartName = "Loading";
|
||||
private const string SearchResultListBoxPartName = "SearchResultListBox";
|
||||
private const string SelectionsListBoxPartName = "SelectionsListBox";
|
||||
private const string SelectionsCounterPartName = "SelectionsCounter";
|
||||
|
||||
private TextBox _searchBox;
|
||||
private ProgressRing _loading;
|
||||
private ListBox _searchResultListBox;
|
||||
private ListBox _selectionsListBox;
|
||||
private TextBlock _selectionsCounter;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="PeoplePicker"/> class.
|
||||
/// </summary>
|
||||
public PeoplePicker()
|
||||
{
|
||||
DefaultStyleKey = typeof(PeoplePicker);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when applying the control template.
|
||||
/// </summary>
|
||||
protected override void OnApplyTemplate()
|
||||
{
|
||||
|
||||
_searchBox = GetTemplateChild("SearchBox") as TextBox;
|
||||
_loading = GetTemplateChild("Loading") as ProgressRing;
|
||||
_searchResultListBox = GetTemplateChild("SearchResultListBox") as ListBox;
|
||||
_selectionsListBox = GetTemplateChild("SelectionsListBox") as ListBox;
|
||||
_selectionsCounter = GetTemplateChild("SelectionsCounter") as TextBlock;
|
||||
|
||||
if (_searchBox != null
|
||||
&& _loading != null
|
||||
&& _searchResultListBox != null
|
||||
&& _selectionsListBox != null
|
||||
&& _selectionsCounter != null)
|
||||
{
|
||||
SearchResultList = new ObservableCollection<Person>();
|
||||
Selections = Selections ?? new ObservableCollection<Person>();
|
||||
if (!this.AllowMultiple)
|
||||
{
|
||||
_selectionsCounter.Visibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
_searchBox.TextChanged += SearchBox_OnTextChanged;
|
||||
_searchResultListBox.SelectionChanged += SearchResultListBox_OnSelectionChanged;
|
||||
|
||||
_selectionsListBox.Tapped += SelectionsListBox_Tapped;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,95 +0,0 @@
|
|||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls.Graph"
|
||||
xmlns:core="using:Microsoft.Xaml.Interactions.Core"
|
||||
xmlns:interactivity="using:Microsoft.Xaml.Interactivity">
|
||||
|
||||
<Style TargetType="controls:PeoplePicker">
|
||||
<Setter Property="Background" Value="{ThemeResource ApplicationPageBackgroundThemeBrush}" />
|
||||
<Setter Property="Foreground" Value="{ThemeResource ApplicationForegroundThemeBrush}" />
|
||||
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="controls:PeoplePicker">
|
||||
<StackPanel Name="PeoplePickerContainer" DataContext="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}}">
|
||||
<Grid>
|
||||
<TextBox Name="SearchBox"
|
||||
Margin="0"
|
||||
AutomationProperties.Name="Keywords"
|
||||
PlaceholderText="{TemplateBinding PlaceholderText}" />
|
||||
<ProgressRing Name="Loading"
|
||||
Margin="0,0,30,0"
|
||||
HorizontalAlignment="Right"
|
||||
AutomationProperties.Name="Progress"
|
||||
FlowDirection="LeftToRight"
|
||||
IsActive="False" />
|
||||
</Grid>
|
||||
<Grid>
|
||||
<StackPanel>
|
||||
<ListBox Name="SelectionsListBox"
|
||||
AutomationProperties.Name="Selections"
|
||||
ItemsSource="{TemplateBinding Selections}">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Grid AutomationProperties.Name="{Binding DisplayName}">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<controls:ProfileCard Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
DisplayMode="LargeProfilePhotoLeft"
|
||||
UserId="{Binding Id}" />
|
||||
<TextBlock Grid.Row="0"
|
||||
Grid.Column="1" />
|
||||
<Button Name="PersonRemoveButton"
|
||||
Tag="{Binding}"
|
||||
Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Width="48"
|
||||
Height="48"
|
||||
Margin="0"
|
||||
HorizontalAlignment="Right"
|
||||
AutomationProperties.Name="Remove from selection"
|
||||
Background="Transparent"
|
||||
BorderThickness="0"
|
||||
FlowDirection="LeftToRight">
|
||||
<SymbolIcon Symbol="Cancel" />
|
||||
</Button>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
<ListBox.ItemContainerStyle>
|
||||
<Style TargetType="ListBoxItem">
|
||||
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
|
||||
</Style>
|
||||
</ListBox.ItemContainerStyle>
|
||||
</ListBox>
|
||||
<TextBlock Name="SelectionsCounter"
|
||||
Visibility="Visible"
|
||||
AutomationProperties.Name="Selections Counter">
|
||||
<Run><Binding Path="Selections.Count"></Binding></Run>
|
||||
<Run> selected</Run>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<ListBox Name="SearchResultListBox"
|
||||
Canvas.ZIndex="100"
|
||||
AutomationProperties.Name="Search Results"
|
||||
ItemsSource="{TemplateBinding SearchResultList}"
|
||||
Visibility="Collapsed">
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<controls:ProfileCard AutomationProperties.Name="{Binding DisplayName}"
|
||||
DisplayMode="LargeProfilePhotoLeft"
|
||||
UserId="{Binding Id}" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
|
@ -1,35 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
using System;
|
||||
using Microsoft.Graph;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
/// <summary>
|
||||
/// Arguments relating to the people selected event of <see cref="PeoplePicker"/> control
|
||||
/// </summary>
|
||||
public class PeopleSelectionChangedEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets selected file
|
||||
/// </summary>
|
||||
public ObservableCollection<Person> Selections { get; private set; }
|
||||
|
||||
internal PeopleSelectionChangedEventArgs(ObservableCollection<Person> selections)
|
||||
{
|
||||
Selections = selections;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the events for the <see cref="ProfileCard"/> control.
|
||||
/// </summary>
|
||||
public partial class ProfileCard : Control
|
||||
{
|
||||
private static void OnUserIdPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
=> (d as ProfileCard).FetchUserInfo();
|
||||
|
||||
private static void OnDisplayModePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var profileCard = d as ProfileCard;
|
||||
ProfileCardItem profileItem = profileCard.CurrentProfileItem.Clone();
|
||||
profileItem.DisplayMode = (ViewType)e.NewValue;
|
||||
profileCard.CurrentProfileItem = profileItem;
|
||||
}
|
||||
|
||||
private static void OnDefaultValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
var profileCard = d as ProfileCard;
|
||||
var aadManager = AadAuthenticationManager.Instance;
|
||||
|
||||
if (!AadAuthenticationManager.Instance.IsAuthenticated
|
||||
|| string.IsNullOrEmpty(profileCard.UserId)
|
||||
|| profileCard.UserId.Equals("Invalid UserId"))
|
||||
{
|
||||
profileCard.InitUserProfile();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,155 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines the properties for the <see cref="ProfileCard"/> control.
|
||||
/// </summary>
|
||||
public partial class ProfileCard : Control
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets required delegated permissions for the <see cref="ProfileCard"/> control
|
||||
/// </summary>
|
||||
public static string[] RequiredDelegatedPermissions
|
||||
{
|
||||
get
|
||||
{
|
||||
return new string[] { "User.Read", "User.ReadBasic.All" };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="UserId"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty UserIdProperty = DependencyProperty.Register(
|
||||
nameof(UserId),
|
||||
typeof(string),
|
||||
typeof(ProfileCard),
|
||||
new PropertyMetadata(string.Empty, OnUserIdPropertyChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="DisplayMode"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty DisplayModeProperty = DependencyProperty.Register(
|
||||
nameof(DisplayMode),
|
||||
typeof(ViewType),
|
||||
typeof(ProfileCard),
|
||||
new PropertyMetadata(ViewType.PictureOnly, OnDisplayModePropertyChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="DefaultImage"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty DefaultImageProperty = DependencyProperty.Register(
|
||||
nameof(DefaultImage),
|
||||
typeof(BitmapImage),
|
||||
typeof(ProfileCard),
|
||||
new PropertyMetadata(null, OnDefaultValuePropertyChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="LargeProfileTitleDefaultText"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty LargeProfileTitleDefaultTextProperty = DependencyProperty.Register(
|
||||
nameof(LargeProfileTitleDefaultText),
|
||||
typeof(string),
|
||||
typeof(ProfileCard),
|
||||
new PropertyMetadata(string.Empty, OnDefaultValuePropertyChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="LargeProfileMailDefaultText"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty LargeProfileMailDefaultTextProperty = DependencyProperty.Register(
|
||||
nameof(LargeProfileMailDefaultText),
|
||||
typeof(string),
|
||||
typeof(ProfileCard),
|
||||
new PropertyMetadata(string.Empty, OnDefaultValuePropertyChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Identifies the <see cref="NormalMailDefaultText"/> dependency property.
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty NormalMailDefaultTextProperty = DependencyProperty.Register(
|
||||
nameof(NormalMailDefaultText),
|
||||
typeof(string),
|
||||
typeof(ProfileCard),
|
||||
new PropertyMetadata(string.Empty, OnDefaultValuePropertyChanged));
|
||||
|
||||
internal static readonly DependencyProperty CurrentProfileItemProperty = DependencyProperty.Register(
|
||||
nameof(CurrentProfileItem),
|
||||
typeof(ProfileCardItem),
|
||||
typeof(ProfileCard),
|
||||
new PropertyMetadata(new ProfileCardItem()));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets user unique identifier.
|
||||
/// </summary>
|
||||
public string UserId
|
||||
{
|
||||
get { return ((string)GetValue(UserIdProperty))?.Trim(); }
|
||||
set { SetValue(UserIdProperty, value?.Trim()); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the visual layout of the control. Default is PictureOnly.
|
||||
/// </summary>
|
||||
public ViewType DisplayMode
|
||||
{
|
||||
get { return (ViewType)GetValue(DisplayModeProperty); }
|
||||
set { SetValue(DisplayModeProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default image when no user is signed in.
|
||||
/// </summary>
|
||||
public BitmapImage DefaultImage
|
||||
{
|
||||
get { return (BitmapImage)GetValue(DefaultImageProperty); }
|
||||
set { SetValue(DefaultImageProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default title text in LargeProfilePhotoLeft mode or LargeProfilePhotoRight mode when no user is signed in.
|
||||
/// </summary>
|
||||
public string LargeProfileTitleDefaultText
|
||||
{
|
||||
get { return (string)GetValue(LargeProfileTitleDefaultTextProperty); }
|
||||
set { SetValue(LargeProfileTitleDefaultTextProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default secondary mail text in LargeProfilePhotoLeft mode or LargeProfilePhotoRight mode when no user is signed in.
|
||||
/// </summary>
|
||||
public string LargeProfileMailDefaultText
|
||||
{
|
||||
get { return (string)GetValue(LargeProfileMailDefaultTextProperty); }
|
||||
set { SetValue(LargeProfileMailDefaultTextProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the default mail text in EmailOnly mode when no user is signed in.
|
||||
/// </summary>
|
||||
public string NormalMailDefaultText
|
||||
{
|
||||
get { return (string)GetValue(NormalMailDefaultTextProperty); }
|
||||
set { SetValue(NormalMailDefaultTextProperty, value); }
|
||||
}
|
||||
|
||||
internal ProfileCardItem CurrentProfileItem
|
||||
{
|
||||
get { return (ProfileCardItem)GetValue(CurrentProfileItemProperty); }
|
||||
set { SetValue(CurrentProfileItemProperty, value); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Graph;
|
||||
using Windows.UI.Core;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
/// <summary>
|
||||
/// The Profile Card control is a simple way to display a user in multiple different formats and mixes of name/image/e-mail.
|
||||
/// </summary>
|
||||
public partial class ProfileCard : Control
|
||||
{
|
||||
private static readonly BitmapImage PersonPhoto = new BitmapImage(new Uri("ms-appx:///Microsoft.Toolkit.Uwp.UI.Controls/Graph/Assets/person.png"));
|
||||
private ContentControl _contentPresenter;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ProfileCard"/> class.
|
||||
/// </summary>
|
||||
public ProfileCard()
|
||||
{
|
||||
DefaultStyleKey = typeof(ProfileCard);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override default OnApplyTemplate to initialize child controls
|
||||
/// </summary>
|
||||
protected override void OnApplyTemplate()
|
||||
{
|
||||
base.OnApplyTemplate();
|
||||
|
||||
_contentPresenter = GetTemplateChild("ContentPresenter") as ContentControl;
|
||||
if (_contentPresenter != null)
|
||||
{
|
||||
_contentPresenter.ContentTemplateSelector = new ProfileDisplayModeTemplateSelector(_contentPresenter);
|
||||
}
|
||||
|
||||
FetchUserInfo();
|
||||
}
|
||||
|
||||
private async void FetchUserInfo()
|
||||
{
|
||||
if (string.IsNullOrEmpty(UserId) || UserId.Equals("Invalid UserId"))
|
||||
{
|
||||
InitUserProfile();
|
||||
}
|
||||
else
|
||||
{
|
||||
GraphServiceClient graphClient = await AadAuthenticationManager.Instance.GetGraphServiceClientAsync();
|
||||
try
|
||||
{
|
||||
var user = await graphClient.Users[UserId].Request().GetAsync();
|
||||
var profileItem = new ProfileCardItem()
|
||||
{
|
||||
NormalMail = user.Mail,
|
||||
LargeProfileTitle = user.DisplayName,
|
||||
LargeProfileMail = user.Mail,
|
||||
DisplayMode = DisplayMode
|
||||
};
|
||||
|
||||
if (string.IsNullOrEmpty(user.Mail))
|
||||
{
|
||||
profileItem.UserPhoto = DefaultImage ?? PersonPhoto;
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
using (Stream photoStream = await graphClient.Users[UserId].Photo.Content.Request().GetAsync())
|
||||
using (var ras = photoStream.AsRandomAccessStream())
|
||||
{
|
||||
var bitmapImage = new BitmapImage();
|
||||
await bitmapImage.SetSourceAsync(ras);
|
||||
profileItem.UserPhoto = bitmapImage;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// Swallow error in case of no photo found
|
||||
profileItem.UserPhoto = DefaultImage ?? PersonPhoto;
|
||||
}
|
||||
}
|
||||
|
||||
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
CurrentProfileItem = profileItem;
|
||||
});
|
||||
}
|
||||
catch (ServiceException ex)
|
||||
{
|
||||
// Swallow error in case of no user id found
|
||||
if (!ex.Error.Code.Equals("Request_ResourceNotFound"))
|
||||
{
|
||||
throw;
|
||||
}
|
||||
|
||||
await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
|
||||
{
|
||||
UserId = "Invalid UserId";
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InitUserProfile()
|
||||
{
|
||||
var profileItem = new ProfileCardItem()
|
||||
{
|
||||
UserPhoto = DefaultImage ?? PersonPhoto,
|
||||
NormalMail = NormalMailDefaultText ?? string.Empty,
|
||||
LargeProfileTitle = LargeProfileTitleDefaultText ?? string.Empty,
|
||||
LargeProfileMail = LargeProfileMailDefaultText ?? string.Empty,
|
||||
DisplayMode = DisplayMode
|
||||
};
|
||||
|
||||
CurrentProfileItem = profileItem;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,98 +0,0 @@
|
|||
<ResourceDictionary
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls.Graph"
|
||||
xmlns:converters="using:Microsoft.Toolkit.Uwp.UI.Converters">
|
||||
|
||||
<converters:StringVisibilityConverter x:Key="StringVisibilityConverter" />
|
||||
|
||||
<Style x:Key="ProfileCardImageBorderStyle"
|
||||
TargetType="Border">
|
||||
<Setter Property="Width" Value="80" />
|
||||
<Setter Property="Height" Value="80" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ProfileCardImageEllipseStyle"
|
||||
TargetType="Ellipse">
|
||||
<Setter Property="Width" Value="64" />
|
||||
<Setter Property="Height" Value="64" />
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ProfileCardLargeProfileStackPanelStyle"
|
||||
TargetType="StackPanel">
|
||||
<Setter Property="Height" Value="80" />
|
||||
<Setter Property="Orientation" Value="Horizontal" />
|
||||
</Style>
|
||||
|
||||
<Style x:Key="ProfileCardLargeProfileTextBlockStyle"
|
||||
TargetType="TextBlock">
|
||||
<Setter Property="FontSize" Value="24" />
|
||||
<Setter Property="Margin" Value="0 0 0 4" />
|
||||
</Style>
|
||||
|
||||
<Style TargetType="controls:ProfileCard">
|
||||
<Setter Property="IsTabStop" Value="False" />
|
||||
<Setter Property="Background" Value="{ThemeResource ApplicationPageBackgroundThemeBrush}" />
|
||||
<Setter Property="Foreground" Value="{ThemeResource ApplicationForegroundThemeBrush}" />
|
||||
<Setter Property="FontFamily" Value="{ThemeResource ContentControlThemeFontFamily}" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="controls:ProfileCard">
|
||||
<Grid>
|
||||
<ContentControl x:Name="ContentPresenter" Content="{TemplateBinding CurrentProfileItem}">
|
||||
<ContentControl.Resources>
|
||||
<DataTemplate x:Key="PictureOnly">
|
||||
<Grid HorizontalAlignment="Left">
|
||||
<Border Style="{ThemeResource ProfileCardImageBorderStyle}">
|
||||
<Ellipse Style="{ThemeResource ProfileCardImageEllipseStyle}">
|
||||
<Ellipse.Fill>
|
||||
<ImageBrush Stretch="UniformToFill" ImageSource="{Binding UserPhoto}"/>
|
||||
</Ellipse.Fill>
|
||||
</Ellipse>
|
||||
</Border>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="EmailOnly">
|
||||
<Grid HorizontalAlignment="Left">
|
||||
<TextBlock Text="{Binding NormalMail}" VerticalAlignment="Center" Padding="10 0 10 0"/>
|
||||
</Grid>
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="LargeProfilePhotoLeft">
|
||||
<StackPanel Style="{ThemeResource ProfileCardLargeProfileStackPanelStyle}">
|
||||
<Border Style="{ThemeResource ProfileCardImageBorderStyle}" Margin="0 0 15 0">
|
||||
<Ellipse Style="{ThemeResource ProfileCardImageEllipseStyle}">
|
||||
<Ellipse.Fill>
|
||||
<ImageBrush Stretch="UniformToFill" ImageSource="{Binding UserPhoto}"/>
|
||||
</Ellipse.Fill>
|
||||
</Ellipse>
|
||||
</Border>
|
||||
<StackPanel VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding LargeProfileTitle}" Style="{ThemeResource ProfileCardLargeProfileTextBlockStyle}"/>
|
||||
<TextBlock Text="{Binding LargeProfileMail}" Visibility="{Binding LargeProfileMail, Converter={StaticResource StringVisibilityConverter}}"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
<DataTemplate x:Key="LargeProfilePhotoRight">
|
||||
<StackPanel Style="{ThemeResource ProfileCardLargeProfileStackPanelStyle}">
|
||||
<StackPanel VerticalAlignment="Center">
|
||||
<TextBlock Text="{Binding LargeProfileTitle}" Style="{ThemeResource ProfileCardLargeProfileTextBlockStyle}"/>
|
||||
<TextBlock Text="{Binding LargeProfileMail}" Visibility="{Binding LargeProfileMail, Converter={StaticResource StringVisibilityConverter}}"/>
|
||||
</StackPanel>
|
||||
<Border Style="{ThemeResource ProfileCardImageBorderStyle}" Margin="15 0 0 0">
|
||||
<Ellipse Style="{ThemeResource ProfileCardImageEllipseStyle}">
|
||||
<Ellipse.Fill>
|
||||
<ImageBrush Stretch="UniformToFill" ImageSource="{Binding UserPhoto}"/>
|
||||
</Ellipse.Fill>
|
||||
</Ellipse>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ContentControl.Resources>
|
||||
</ContentControl>
|
||||
</Grid>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
|
@ -1,34 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
internal class ProfileCardItem
|
||||
{
|
||||
public string NormalMail { get; set; }
|
||||
|
||||
public string LargeProfileTitle { get; set; }
|
||||
|
||||
public string LargeProfileMail { get; set; }
|
||||
|
||||
public BitmapImage UserPhoto { get; set; }
|
||||
|
||||
public ViewType DisplayMode { get; set; }
|
||||
|
||||
public ProfileCardItem Clone()
|
||||
{
|
||||
return (ProfileCardItem)MemberwiseClone();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,63 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
internal class ProfileDisplayModeTemplateSelector : DataTemplateSelector
|
||||
{
|
||||
private ContentControl _contentPresenter;
|
||||
|
||||
internal ProfileDisplayModeTemplateSelector(ContentControl contentPresenter)
|
||||
{
|
||||
_contentPresenter = contentPresenter;
|
||||
}
|
||||
|
||||
private DataTemplate SelectItemTemplate(object item)
|
||||
{
|
||||
DataTemplate dataTemplate = null;
|
||||
|
||||
if (item != null && item is ProfileCardItem profileItem)
|
||||
{
|
||||
switch (profileItem.DisplayMode)
|
||||
{
|
||||
case ViewType.EmailOnly:
|
||||
dataTemplate = _contentPresenter.Resources["EmailOnly"] as DataTemplate;
|
||||
break;
|
||||
case ViewType.PictureOnly:
|
||||
dataTemplate = _contentPresenter.Resources["PictureOnly"] as DataTemplate;
|
||||
break;
|
||||
case ViewType.LargeProfilePhotoLeft:
|
||||
dataTemplate = _contentPresenter.Resources["LargeProfilePhotoLeft"] as DataTemplate;
|
||||
break;
|
||||
case ViewType.LargeProfilePhotoRight:
|
||||
dataTemplate = _contentPresenter.Resources["LargeProfilePhotoRight"] as DataTemplate;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return dataTemplate;
|
||||
}
|
||||
|
||||
protected override DataTemplate SelectTemplateCore(object item)
|
||||
{
|
||||
return SelectItemTemplate(item);
|
||||
}
|
||||
|
||||
protected override DataTemplate SelectTemplateCore(object item, DependencyObject container)
|
||||
{
|
||||
return SelectItemTemplate(item);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
/// <summary>
|
||||
/// The visual layout of the <see cref="ProfileCard"/> control. Default is PictureOnly.
|
||||
/// </summary>
|
||||
public enum ViewType
|
||||
{
|
||||
/// <summary>
|
||||
/// Only the user photo is shown.
|
||||
/// </summary>
|
||||
PictureOnly = 0,
|
||||
|
||||
/// <summary>
|
||||
/// Only the user email is shown.
|
||||
/// </summary>
|
||||
EmailOnly = 1,
|
||||
|
||||
/// <summary>
|
||||
/// A basic user profile is shown, and the user photo is place on the left side.
|
||||
/// </summary>
|
||||
LargeProfilePhotoLeft = 2,
|
||||
|
||||
/// <summary>
|
||||
/// A basic user profile is shown, and the user photo is place on the right side.
|
||||
/// </summary>
|
||||
LargeProfilePhotoRight = 3
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
/// <summary>
|
||||
/// Determines how file details panel is displayed in the <see cref="SharePointFileList"/> control.
|
||||
/// </summary>
|
||||
public enum DetailPaneDisplayMode
|
||||
{
|
||||
/// <summary>
|
||||
/// Hide show DetailPane
|
||||
/// </summary>
|
||||
Disabled,
|
||||
|
||||
/// <summary>
|
||||
/// Show DetailPane aside
|
||||
/// </summary>
|
||||
Side,
|
||||
|
||||
/// <summary>
|
||||
/// Show DetailPane at bottom
|
||||
/// </summary>
|
||||
Bottom,
|
||||
|
||||
/// <summary>
|
||||
/// Show DetailPane over list
|
||||
/// </summary>
|
||||
Full
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
using System;
|
||||
using Microsoft.Graph;
|
||||
using Windows.UI.Xaml.Data;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
/// <summary>
|
||||
/// Get icon of DriveItem
|
||||
/// </summary>
|
||||
internal class DriveItemIconConverter : IValueConverter
|
||||
{
|
||||
private static readonly string OfficeIcon = "https://static2.sharepointonline.com/files/fabric/assets/brand-icons/document/png/{0}_32x1_5.png";
|
||||
private static readonly string LocalIcon = "ms-appx:///Microsoft.Toolkit.Uwp.UI.Controls/Graph/Assets/{0}";
|
||||
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
DriveItem driveItem = value as DriveItem;
|
||||
|
||||
if (driveItem.Folder != null)
|
||||
{
|
||||
return string.Format(LocalIcon, "folder.svg");
|
||||
}
|
||||
else if (driveItem.File != null)
|
||||
{
|
||||
if (driveItem.File.MimeType.StartsWith("image"))
|
||||
{
|
||||
return string.Format(LocalIcon, "photo.png");
|
||||
}
|
||||
else if (driveItem.File.MimeType.StartsWith("application/vnd.openxmlformats-officedocument"))
|
||||
{
|
||||
int index = driveItem.Name.LastIndexOf('.');
|
||||
if (index != -1)
|
||||
{
|
||||
string ext = driveItem.Name.Substring(index + 1);
|
||||
return string.Format(OfficeIcon, ext);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (driveItem.Package != null)
|
||||
{
|
||||
switch (driveItem.Package.Type)
|
||||
{
|
||||
case "oneNote":
|
||||
return string.Format(OfficeIcon, "one");
|
||||
}
|
||||
}
|
||||
|
||||
return string.Format(LocalIcon, "genericfile.png");
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,33 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
using System;
|
||||
using Microsoft.Graph;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
/// <summary>
|
||||
/// Arguments relating to a file selected event of SharePointFiles control
|
||||
/// </summary>
|
||||
public class FileSelectedEventArgs
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets selected file
|
||||
/// </summary>
|
||||
public DriveItem FileSelected { get; private set; }
|
||||
|
||||
internal FileSelectedEventArgs(DriveItem fileSelected)
|
||||
{
|
||||
FileSelected = fileSelected;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,32 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
using System;
|
||||
using Microsoft.Toolkit.Extensions;
|
||||
using Windows.UI.Xaml.Data;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
internal class FileSizeConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
long size = (long)value;
|
||||
return size.ToFileSizeString();
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, string language)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// All common long extensions should go here
|
||||
/// </summary>
|
||||
internal static class Int64Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Translate numeric file size to string format.
|
||||
/// </summary>
|
||||
/// <param name="size">file size in bytes.</param>
|
||||
/// <returns>Returns file size string.</returns>
|
||||
public static string ToFileSizeString(this long size)
|
||||
{
|
||||
if (size < 1024)
|
||||
{
|
||||
return size.ToString("F0") + " bytes";
|
||||
}
|
||||
else if ((size >> 10) < 1024)
|
||||
{
|
||||
return (size / (float)1024).ToString("F1") + " KB";
|
||||
}
|
||||
else if ((size >> 20) < 1024)
|
||||
{
|
||||
return ((size >> 10) / (float)1024).ToString("F1") + " MB";
|
||||
}
|
||||
else if ((size >> 30) < 1024)
|
||||
{
|
||||
return ((size >> 20) / (float)1024).ToString("F1") + " GB";
|
||||
}
|
||||
else if ((size >> 40) < 1024)
|
||||
{
|
||||
return ((size >> 30) / (float)1024).ToString("F1") + " TB";
|
||||
}
|
||||
else if ((size >> 50) < 1024)
|
||||
{
|
||||
return ((size >> 40) / (float)1024).ToString("F1") + " PB";
|
||||
}
|
||||
else
|
||||
{
|
||||
return ((size >> 50) / (float)1024).ToString("F0") + " EB";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,135 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
/// <summary>
|
||||
/// The SharePointFiles Control displays a simple list of SharePoint Files.
|
||||
/// </summary>
|
||||
public partial class SharePointFileList
|
||||
{
|
||||
/// <summary>
|
||||
/// Key of the VisualStateGroup to control nav buttons
|
||||
/// </summary>
|
||||
private const string NavStates = "NavStates";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the VisualState when display folder in readonly mode
|
||||
/// </summary>
|
||||
private const string NavStatesFolderReadonly = "FolderReadOnly";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the VisualState when display folder in edit mode
|
||||
/// </summary>
|
||||
private const string NavStatesFolderEdit = "FolderEdit";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the VisualState when display file in readonly mode
|
||||
/// </summary>
|
||||
private const string NavStatesFileReadonly = "FileReadonly";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the VisualState when display file in edit mode
|
||||
/// </summary>
|
||||
private const string NavStatesFileEdit = "FileEdit";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the VisualStateGroup to control uploading status
|
||||
/// </summary>
|
||||
private const string UploadStatus = "UploadStatus";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the VisualState when not uploading files
|
||||
/// </summary>
|
||||
private const string UploadStatusNotUploading = "NotUploading";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the VisualState when uploading files
|
||||
/// </summary>
|
||||
private const string UploadStatusUploading = "Uploading";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the VisualState when uploading error occurs
|
||||
/// </summary>
|
||||
private const string UploadStatusError = "Error";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the VisualStateGroup to control detail pane
|
||||
/// </summary>
|
||||
private const string DetailPaneStates = "DetailPaneStates";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the VisualState when detail pane is hidden
|
||||
/// </summary>
|
||||
private const string DetailPaneStatesHide = "Hide";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the VisualState when detail pane is at right side
|
||||
/// </summary>
|
||||
private const string DetailPaneStatesSide = "Side";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the VisualState when detail pane is at bottom
|
||||
/// </summary>
|
||||
private const string DetailPaneStatesBottom = "Bottom";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the VisualState when detail pane is in full mode
|
||||
/// </summary>
|
||||
private const string DetailPaneStatesFull = "Full";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the ListView that contains file list
|
||||
/// </summary>
|
||||
private const string ControlFileList = "list";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the back button that contains file list
|
||||
/// </summary>
|
||||
private const string ControlBack = "back";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the upload button that contains file list
|
||||
/// </summary>
|
||||
private const string ControlUpload = "upload";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the share button that contains file list
|
||||
/// </summary>
|
||||
private const string ControlShare = "share";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the download button that contains file list
|
||||
/// </summary>
|
||||
private const string ControlDownload = "download";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the delete button that contains file list
|
||||
/// </summary>
|
||||
private const string ControlDelete = "delete";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the error button that contains file list
|
||||
/// </summary>
|
||||
private const string ControlError = "error";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the cancel button that contains file list
|
||||
/// </summary>
|
||||
private const string ControlCancel = "cancel";
|
||||
|
||||
/// <summary>
|
||||
/// Key of the has more button that contains file list
|
||||
/// </summary>
|
||||
private const string ControlLoadMore = "hasMore";
|
||||
}
|
||||
}
|
|
@ -1,270 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Graph;
|
||||
using Windows.ApplicationModel.DataTransfer;
|
||||
using Windows.Storage;
|
||||
using Windows.Storage.Pickers;
|
||||
using Windows.UI.Popups;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
using Windows.UI.Xaml.Media.Imaging;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
/// <summary>
|
||||
/// The SharePointFiles Control displays a simple list of SharePoint Files.
|
||||
/// </summary>
|
||||
public partial class SharePointFileList
|
||||
{
|
||||
private static async void DriveUrlPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (AadAuthenticationManager.Instance.IsAuthenticated)
|
||||
{
|
||||
SharePointFileList control = d as SharePointFileList;
|
||||
GraphServiceClient graphServiceClient = await AadAuthenticationManager.Instance.GetGraphServiceClientAsync();
|
||||
if (graphServiceClient != null && !string.IsNullOrWhiteSpace(control.DriveUrl))
|
||||
{
|
||||
if (Uri.IsWellFormedUriString(control.DriveUrl, UriKind.Absolute))
|
||||
{
|
||||
await control.InitDriveAsync(control.DriveUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DetailPanePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
SharePointFileList control = d as SharePointFileList;
|
||||
if (control.IsDetailPaneVisible)
|
||||
{
|
||||
control.ShowDetailsPane();
|
||||
}
|
||||
}
|
||||
|
||||
private async void Back_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (DetailPane == DetailPaneDisplayMode.Full && IsDetailPaneVisible)
|
||||
{
|
||||
IsDetailPaneVisible = false;
|
||||
HideDetailsPane();
|
||||
}
|
||||
else if (_driveItemPath.Count > 1)
|
||||
{
|
||||
_driveItemPath.Pop();
|
||||
string parentItemId = _driveItemPath.Peek();
|
||||
if (_driveItemPath.Count == 1)
|
||||
{
|
||||
BackButtonVisibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
await LoadFilesAsync(parentItemId);
|
||||
}
|
||||
}
|
||||
|
||||
private async void Upload_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
ErrorMessage = string.Empty;
|
||||
FileOpenPicker picker = new FileOpenPicker();
|
||||
picker.FileTypeFilter.Add("*");
|
||||
StorageFile file = await picker.PickSingleFileAsync();
|
||||
if (file != null)
|
||||
{
|
||||
string driveItemId = _driveItemPath.Peek();
|
||||
using (Stream inputStream = await file.OpenStreamForReadAsync())
|
||||
{
|
||||
if (inputStream.Length < 1024 * 1024 * 4)
|
||||
{
|
||||
FileUploading++;
|
||||
StatusMessage = string.Format(UploadingFilesMessageTemplate, FileUploading);
|
||||
VisualStateManager.GoToState(this, UploadStatusUploading, false);
|
||||
try
|
||||
{
|
||||
GraphServiceClient graphServiceClient = await _aadAuthenticationManager.GetGraphServiceClientAsync();
|
||||
await graphServiceClient.Drives[_driveId].Items[driveItemId].ItemWithPath(file.Name).Content.Request().PutAsync<DriveItem>(inputStream, _cancelUpload.Token);
|
||||
VisualStateManager.GoToState(this, UploadStatusNotUploading, false);
|
||||
FileUploading--;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
FileUploading--;
|
||||
ErrorMessage = ex.Message;
|
||||
VisualStateManager.GoToState(this, UploadStatusError, false);
|
||||
}
|
||||
|
||||
await LoadFilesAsync(driveItemId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void Share_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_list.SelectedItem is DriveItem driveItem)
|
||||
{
|
||||
GraphServiceClient graphServiceClient = await _aadAuthenticationManager.GetGraphServiceClientAsync();
|
||||
Permission link = await graphServiceClient.Drives[_driveId].Items[driveItem.Id].CreateLink("view", "organization").Request().PostAsync();
|
||||
MessageDialog dialog = new MessageDialog(link.Link.WebUrl, ShareLinkCopiedMessage);
|
||||
DataPackage package = new DataPackage();
|
||||
package.SetText(link.Link.WebUrl);
|
||||
Clipboard.SetContent(package);
|
||||
await dialog.ShowAsync();
|
||||
}
|
||||
}
|
||||
|
||||
private async void Download_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_list.SelectedItem is DriveItem driveItem)
|
||||
{
|
||||
GraphServiceClient graphServiceClient = await _aadAuthenticationManager.GetGraphServiceClientAsync();
|
||||
FileSavePicker picker = new FileSavePicker();
|
||||
picker.FileTypeChoices.Add(AllFilesMessage, new List<string>() { driveItem.Name.Substring(driveItem.Name.LastIndexOf(".")) });
|
||||
picker.SuggestedFileName = driveItem.Name;
|
||||
picker.SuggestedStartLocation = PickerLocationId.DocumentsLibrary;
|
||||
StorageFile file = await picker.PickSaveFileAsync();
|
||||
if (file != null)
|
||||
{
|
||||
using (Stream inputStream = await graphServiceClient.Drives[_driveId].Items[driveItem.Id].Content.Request().GetAsync())
|
||||
{
|
||||
using (Stream outputStream = await file.OpenStreamForWriteAsync())
|
||||
{
|
||||
await inputStream.CopyToAsync(outputStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void Delete_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (_list.SelectedItem is DriveItem driveItem)
|
||||
{
|
||||
MessageDialog confirmDialog = new MessageDialog(DeleteConfirmMessage);
|
||||
confirmDialog.Commands.Add(new UICommand(DeleteConfirmOkMessage, cmd => { }, commandId: 0));
|
||||
confirmDialog.Commands.Add(new UICommand(DeleteConfirmCancelMessage, cmd => { }, commandId: 1));
|
||||
|
||||
confirmDialog.DefaultCommandIndex = 0;
|
||||
confirmDialog.CancelCommandIndex = 1;
|
||||
|
||||
IUICommand result = await confirmDialog.ShowAsync();
|
||||
|
||||
if ((int)result.Id == 0)
|
||||
{
|
||||
GraphServiceClient graphServiceClient = await _aadAuthenticationManager.GetGraphServiceClientAsync();
|
||||
await graphServiceClient.Drives[_driveId].Items[driveItem.Id].Request().DeleteAsync();
|
||||
string driveItemId = _driveItemPath.Peek();
|
||||
await LoadFilesAsync(driveItemId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void ShowErrorDetails_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
MessageDialog messageDialog = new MessageDialog(ErrorMessage);
|
||||
await messageDialog.ShowAsync();
|
||||
}
|
||||
|
||||
private async void LoadMore_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
await LoadNextPageAsync();
|
||||
}
|
||||
|
||||
private void Cancel_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
_cancelUpload.Cancel(false);
|
||||
_cancelUpload.Dispose();
|
||||
_cancelUpload = new CancellationTokenSource();
|
||||
}
|
||||
|
||||
private async void List_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
||||
{
|
||||
if (_list.SelectedItem is DriveItem driveItem)
|
||||
{
|
||||
_cancelGetDetails.Cancel(false);
|
||||
_cancelGetDetails.Dispose();
|
||||
_cancelGetDetails = new CancellationTokenSource();
|
||||
if (driveItem.File != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
SelectedFile = driveItem;
|
||||
FileSize = driveItem.Size ?? 0;
|
||||
LastModified = driveItem.LastModifiedDateTime?.LocalDateTime.ToString() ?? string.Empty;
|
||||
if (FileSelected != null)
|
||||
{
|
||||
FileSelected.Invoke(this, new FileSelectedEventArgs(driveItem));
|
||||
}
|
||||
|
||||
ThumbnailImageSource = null;
|
||||
VisualStateManager.GoToState(this, NavStatesFileReadonly, false);
|
||||
GraphServiceClient graphServiceClient = await _aadAuthenticationManager.GetGraphServiceClientAsync();
|
||||
Task<IDriveItemPermissionsCollectionPage> taskPermissions = graphServiceClient.Drives[_driveId].Items[driveItem.Id].Permissions.Request().GetAsync(_cancelGetDetails.Token);
|
||||
IDriveItemPermissionsCollectionPage permissions = await taskPermissions;
|
||||
if (!taskPermissions.IsCanceled)
|
||||
{
|
||||
foreach (Permission permission in permissions)
|
||||
{
|
||||
if (permission.Roles.Contains("write") || permission.Roles.Contains("owner"))
|
||||
{
|
||||
VisualStateManager.GoToState(this, NavStatesFileEdit, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Task<IDriveItemThumbnailsCollectionPage> taskThumbnails = graphServiceClient.Drives[_driveId].Items[driveItem.Id].Thumbnails.Request().GetAsync(_cancelGetDetails.Token);
|
||||
IDriveItemThumbnailsCollectionPage thumbnails = await taskThumbnails;
|
||||
if (!taskThumbnails.IsCanceled)
|
||||
{
|
||||
ThumbnailSet thumbnailsSet = thumbnails.FirstOrDefault();
|
||||
if (thumbnailsSet != null)
|
||||
{
|
||||
ThumbnailImageSource = new BitmapImage(new Uri(thumbnailsSet.Large.Url));
|
||||
}
|
||||
}
|
||||
|
||||
IsDetailPaneVisible = true;
|
||||
ShowDetailsPane();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
SelectedFile = null;
|
||||
FileSize = 0;
|
||||
LastModified = string.Empty;
|
||||
VisualStateManager.GoToState(this, NavStatesFolderReadonly, false);
|
||||
IsDetailPaneVisible = false;
|
||||
HideDetailsPane();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async void List_ItemClick(object sender, ItemClickEventArgs e)
|
||||
{
|
||||
if (e.ClickedItem is DriveItem driveItem && driveItem.Folder != null)
|
||||
{
|
||||
_driveItemPath.Push(driveItem.Id);
|
||||
BackButtonVisibility = Visibility.Visible;
|
||||
await LoadFilesAsync(driveItem.Id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,321 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
using Microsoft.Graph;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Media;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
/// <summary>
|
||||
/// The SharePointFiles Control displays a simple list of SharePoint Files.
|
||||
/// </summary>
|
||||
public partial class SharePointFileList
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets required delegated permissions for the <see cref="SharePointFileList"/> control
|
||||
/// </summary>
|
||||
public static string[] RequiredDelegatedPermissions
|
||||
{
|
||||
get
|
||||
{
|
||||
return new string[] { "User.Read", "Files.ReadWrite.All" };
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Url of OneDrive to display
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty DriveUrlProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(DriveUrl),
|
||||
typeof(string),
|
||||
typeof(SharePointFileList),
|
||||
new PropertyMetadata(string.Empty, DriveUrlPropertyChanged));
|
||||
|
||||
/// <summary>
|
||||
/// How details of a file shows
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty DetailPaneProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(DetailPane),
|
||||
typeof(DetailPaneDisplayMode),
|
||||
typeof(SharePointFileList),
|
||||
new PropertyMetadata(DetailPaneDisplayMode.Disabled, DetailPanePropertyChanged));
|
||||
|
||||
/// <summary>
|
||||
/// Page size of each request
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty PageSizeProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(PageSize),
|
||||
typeof(int),
|
||||
typeof(SharePointFileList),
|
||||
new PropertyMetadata(20));
|
||||
|
||||
/// <summary>
|
||||
/// Share link copied message
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty ShareLinkCopiedMessageProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(ShareLinkCopiedMessage),
|
||||
typeof(string),
|
||||
typeof(SharePointFileList),
|
||||
new PropertyMetadata("Link copied!"));
|
||||
|
||||
/// <summary>
|
||||
/// All files message
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty AllFilesMessageProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(AllFilesMessage),
|
||||
typeof(string),
|
||||
typeof(SharePointFileList),
|
||||
new PropertyMetadata("All Files"));
|
||||
|
||||
/// <summary>
|
||||
/// Delete confirm message
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty DeleteConfirmMessageProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(DeleteConfirmMessage),
|
||||
typeof(string),
|
||||
typeof(SharePointFileList),
|
||||
new PropertyMetadata("Do you want to delete this file?"));
|
||||
|
||||
/// <summary>
|
||||
/// Delete confirm Ok message
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty DeleteConfirmOkMessageProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(DeleteConfirmOkMessage),
|
||||
typeof(string),
|
||||
typeof(SharePointFileList),
|
||||
new PropertyMetadata("OK"));
|
||||
|
||||
/// <summary>
|
||||
/// Delete confirm cancel message
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty DeleteConfirmCancelMessageProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(DeleteConfirmCancelMessage),
|
||||
typeof(string),
|
||||
typeof(SharePointFileList),
|
||||
new PropertyMetadata("Cancel"));
|
||||
|
||||
/// <summary>
|
||||
/// Uploading files message template
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty UploadingFilesMessageTemplateProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(UploadingFilesMessageTemplate),
|
||||
typeof(string),
|
||||
typeof(SharePointFileList),
|
||||
new PropertyMetadata("Uploading {0} files..."));
|
||||
|
||||
internal static readonly DependencyProperty ThumbnailImageSourceProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(ThumbnailImageSource),
|
||||
typeof(ImageSource),
|
||||
typeof(SharePointFileList),
|
||||
new PropertyMetadata(null));
|
||||
|
||||
internal static readonly DependencyProperty HasMoreProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(HasMore),
|
||||
typeof(bool),
|
||||
typeof(SharePointFileList),
|
||||
new PropertyMetadata(false));
|
||||
|
||||
internal static readonly DependencyProperty SelectedFileProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(SelectedFile),
|
||||
typeof(DriveItem),
|
||||
typeof(SharePointFileList),
|
||||
new PropertyMetadata(null));
|
||||
|
||||
internal static readonly DependencyProperty SizeProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(FileSize),
|
||||
typeof(long),
|
||||
typeof(SharePointFileList),
|
||||
new PropertyMetadata(0L));
|
||||
|
||||
internal static readonly DependencyProperty LastModifiedProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(LastModified),
|
||||
typeof(string),
|
||||
typeof(SharePointFileList),
|
||||
null);
|
||||
|
||||
internal static readonly DependencyProperty BackButtonVisibilityProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(BackButtonVisibility),
|
||||
typeof(Visibility),
|
||||
typeof(SharePointFileList),
|
||||
new PropertyMetadata(Visibility.Collapsed));
|
||||
|
||||
internal static readonly DependencyProperty StatusMessageProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(StatusMessage),
|
||||
typeof(string),
|
||||
typeof(SharePointFileList),
|
||||
new PropertyMetadata(string.Empty));
|
||||
|
||||
private static readonly DependencyProperty IsDetailPaneVisibleProperty =
|
||||
DependencyProperty.Register(
|
||||
nameof(IsDetailPaneVisible),
|
||||
typeof(bool),
|
||||
typeof(SharePointFileList),
|
||||
new PropertyMetadata(false));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets drive or SharePoint document library URL to display
|
||||
/// </summary>
|
||||
public string DriveUrl
|
||||
{
|
||||
get { return ((string)GetValue(DriveUrlProperty))?.Trim(); }
|
||||
set { SetValue(DriveUrlProperty, value?.Trim()); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets how DetailPane shows
|
||||
/// </summary>
|
||||
public DetailPaneDisplayMode DetailPane
|
||||
{
|
||||
get { return (DetailPaneDisplayMode)GetValue(DetailPaneProperty); }
|
||||
set { SetValue(DetailPaneProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets page size of each request
|
||||
/// </summary>
|
||||
public int PageSize
|
||||
{
|
||||
get { return (int)GetValue(PageSizeProperty); }
|
||||
set { SetValue(PageSizeProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the message when share link copied
|
||||
/// </summary>
|
||||
public string ShareLinkCopiedMessage
|
||||
{
|
||||
get { return (string)GetValue(ShareLinkCopiedMessageProperty); }
|
||||
set { SetValue(ShareLinkCopiedMessageProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the label of All Files
|
||||
/// </summary>
|
||||
public string AllFilesMessage
|
||||
{
|
||||
get { return (string)GetValue(AllFilesMessageProperty); }
|
||||
set { SetValue(AllFilesMessageProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the message of delete confirm dialog
|
||||
/// </summary>
|
||||
public string DeleteConfirmMessage
|
||||
{
|
||||
get { return (string)GetValue(DeleteConfirmMessageProperty); }
|
||||
set { SetValue(DeleteConfirmMessageProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the caption of ok button in delete confirm dialog
|
||||
/// </summary>
|
||||
public string DeleteConfirmOkMessage
|
||||
{
|
||||
get { return (string)GetValue(DeleteConfirmOkMessageProperty); }
|
||||
set { SetValue(DeleteConfirmOkMessageProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the caption of cancel button in delete confirm dialog
|
||||
/// </summary>
|
||||
public string DeleteConfirmCancelMessage
|
||||
{
|
||||
get { return (string)GetValue(DeleteConfirmCancelMessageProperty); }
|
||||
set { SetValue(DeleteConfirmCancelMessageProperty, value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the template of uploading files
|
||||
/// </summary>
|
||||
public string UploadingFilesMessageTemplate
|
||||
{
|
||||
get { return (string)GetValue(UploadingFilesMessageTemplateProperty); }
|
||||
set { SetValue(UploadingFilesMessageTemplateProperty, value); }
|
||||
}
|
||||
|
||||
internal bool HasMore
|
||||
{
|
||||
get { return (bool)GetValue(HasMoreProperty); }
|
||||
set { SetValue(HasMoreProperty, value); }
|
||||
}
|
||||
|
||||
internal DriveItem SelectedFile
|
||||
{
|
||||
get { return (DriveItem)GetValue(SelectedFileProperty); }
|
||||
set { SetValue(SelectedFileProperty, value); }
|
||||
}
|
||||
|
||||
internal long FileSize
|
||||
{
|
||||
get { return (long)GetValue(SizeProperty); }
|
||||
set { SetValue(SizeProperty, value); }
|
||||
}
|
||||
|
||||
internal string LastModified
|
||||
{
|
||||
get { return (string)GetValue(LastModifiedProperty); }
|
||||
set { SetValue(LastModifiedProperty, value); }
|
||||
}
|
||||
|
||||
internal ImageSource ThumbnailImageSource
|
||||
{
|
||||
get { return (ImageSource)GetValue(ThumbnailImageSourceProperty); }
|
||||
set { SetValue(ThumbnailImageSourceProperty, value); }
|
||||
}
|
||||
|
||||
internal string StatusMessage
|
||||
{
|
||||
get { return (string)GetValue(StatusMessageProperty); }
|
||||
set { SetValue(StatusMessageProperty, value); }
|
||||
}
|
||||
|
||||
internal Visibility BackButtonVisibility
|
||||
{
|
||||
get { return (Visibility)GetValue(BackButtonVisibilityProperty); }
|
||||
set { SetValue(BackButtonVisibilityProperty, value); }
|
||||
}
|
||||
|
||||
private bool IsDetailPaneVisible
|
||||
{
|
||||
get
|
||||
{
|
||||
return (bool)GetValue(IsDetailPaneVisibleProperty);
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
SetValue(IsDetailPaneVisibleProperty, value);
|
||||
}
|
||||
}
|
||||
|
||||
private int FileUploading { get; set; }
|
||||
|
||||
private string ErrorMessage { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,335 +0,0 @@
|
|||
// ******************************************************************
|
||||
// Copyright (c) Microsoft. All rights reserved.
|
||||
// This code is licensed under the MIT License (MIT).
|
||||
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
||||
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
|
||||
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
|
||||
// ******************************************************************
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Graph;
|
||||
using Newtonsoft.Json;
|
||||
using Windows.UI.Xaml;
|
||||
using Windows.UI.Xaml.Controls;
|
||||
|
||||
namespace Microsoft.Toolkit.Uwp.UI.Controls.Graph
|
||||
{
|
||||
/// <summary>
|
||||
/// The SharePointFiles Control displays a simple list of SharePoint Files.
|
||||
/// </summary>
|
||||
[TemplatePart(Name = ControlFileList, Type = typeof(ListView))]
|
||||
[TemplatePart(Name = ControlBack, Type = typeof(Button))]
|
||||
[TemplatePart(Name = ControlCancel, Type = typeof(Button))]
|
||||
[TemplatePart(Name = ControlDelete, Type = typeof(Button))]
|
||||
[TemplatePart(Name = ControlDownload, Type = typeof(Button))]
|
||||
[TemplatePart(Name = ControlLoadMore, Type = typeof(Button))]
|
||||
[TemplatePart(Name = ControlShare, Type = typeof(Button))]
|
||||
[TemplatePart(Name = ControlUpload, Type = typeof(Button))]
|
||||
[TemplatePart(Name = ControlError, Type = typeof(HyperlinkButton))]
|
||||
[TemplateVisualState(Name = UploadStatusNotUploading, GroupName = UploadStatus)]
|
||||
[TemplateVisualState(Name = UploadStatusUploading, GroupName = UploadStatus)]
|
||||
[TemplateVisualState(Name = UploadStatusError, GroupName = UploadStatus)]
|
||||
[TemplateVisualState(Name = DetailPaneStatesHide, GroupName = DetailPaneStates)]
|
||||
[TemplateVisualState(Name = DetailPaneStatesSide, GroupName = DetailPaneStates)]
|
||||
[TemplateVisualState(Name = DetailPaneStatesBottom, GroupName = DetailPaneStates)]
|
||||
[TemplateVisualState(Name = DetailPaneStatesFull, GroupName = DetailPaneStates)]
|
||||
[TemplateVisualState(Name = NavStatesFolderReadonly, GroupName = NavStates)]
|
||||
[TemplateVisualState(Name = NavStatesFolderEdit, GroupName = NavStates)]
|
||||
[TemplateVisualState(Name = NavStatesFileReadonly, GroupName = NavStates)]
|
||||
[TemplateVisualState(Name = NavStatesFileEdit, GroupName = NavStates)]
|
||||
public partial class SharePointFileList : Control
|
||||
{
|
||||
/// <summary>
|
||||
/// File is selected
|
||||
/// </summary>
|
||||
public event EventHandler<FileSelectedEventArgs> FileSelected;
|
||||
|
||||
private string _driveId;
|
||||
private Stack<string> _driveItemPath = new Stack<string>();
|
||||
private IDriveItemChildrenCollectionRequest _nextPageRequest = null;
|
||||
private CancellationTokenSource _cancelUpload = new CancellationTokenSource();
|
||||
private CancellationTokenSource _cancelLoadFile = new CancellationTokenSource();
|
||||
private CancellationTokenSource _cancelGetDetails = new CancellationTokenSource();
|
||||
|
||||
private AadAuthenticationManager _aadAuthenticationManager = AadAuthenticationManager.Instance;
|
||||
private ListView _list;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="SharePointFileList"/> class.
|
||||
/// </summary>
|
||||
public SharePointFileList()
|
||||
{
|
||||
DefaultStyleKey = typeof(SharePointFileList);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called when applying the control template.
|
||||
/// </summary>
|
||||
protected override void OnApplyTemplate()
|
||||
{
|
||||
_list = GetTemplateChild(ControlFileList) as ListView;
|
||||
if (_list != null)
|
||||
{
|
||||
_list.SelectionChanged += List_SelectionChanged;
|
||||
_list.ItemClick += List_ItemClick;
|
||||
}
|
||||
|
||||
Button back = GetTemplateChild(ControlBack) as Button;
|
||||
if (back != null)
|
||||
{
|
||||
back.Click += Back_Click;
|
||||
}
|
||||
|
||||
Button cancel = GetTemplateChild(ControlCancel) as Button;
|
||||
if (cancel != null)
|
||||
{
|
||||
cancel.Click += Cancel_Click;
|
||||
}
|
||||
|
||||
Button delete = GetTemplateChild(ControlDelete) as Button;
|
||||
if (delete != null)
|
||||
{
|
||||
delete.Click += Delete_Click;
|
||||
}
|
||||
|
||||
Button download = GetTemplateChild(ControlDownload) as Button;
|
||||
if (download != null)
|
||||
{
|
||||
download.Click += Download_Click;
|
||||
}
|
||||
|
||||
Button loadMore = GetTemplateChild(ControlLoadMore) as Button;
|
||||
if (loadMore != null)
|
||||
{
|
||||
loadMore.Click += LoadMore_Click;
|
||||
}
|
||||
|
||||
Button share = GetTemplateChild(ControlShare) as Button;
|
||||
if (share != null)
|
||||
{
|
||||
share.Click += Share_Click;
|
||||
}
|
||||
|
||||
Button upload = GetTemplateChild(ControlUpload) as Button;
|
||||
if (upload != null)
|
||||
{
|
||||
upload.Click += Upload_Click;
|
||||
}
|
||||
|
||||
HyperlinkButton error = GetTemplateChild(ControlError) as HyperlinkButton;
|
||||
if (error != null)
|
||||
{
|
||||
error.Click += ShowErrorDetails_Click;
|
||||
}
|
||||
|
||||
base.OnApplyTemplate();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves an appropriate Drive URL from a SharePoint document library root URL
|
||||
/// </summary>
|
||||
/// <param name="rawDocLibUrl">Raw URL for SharePoint document library</param>
|
||||
/// <returns>Drive URL</returns>
|
||||
public async Task<string> GetDriveUrlFromSharePointUrlAsync(string rawDocLibUrl)
|
||||
{
|
||||
if (string.IsNullOrEmpty(rawDocLibUrl))
|
||||
{
|
||||
return rawDocLibUrl;
|
||||
}
|
||||
|
||||
rawDocLibUrl = WebUtility.UrlDecode(rawDocLibUrl);
|
||||
|
||||
Match match = Regex.Match(rawDocLibUrl, @"(https?://([^/]+)((/[^/?]+)*?)(/[^/?]+))(/(Forms/\w+.aspx)?)?(\?.*)?$", RegexOptions.IgnoreCase);
|
||||
string docLibUrl = match.Groups[1].Value;
|
||||
string hostName = match.Groups[2].Value;
|
||||
string siteRelativePath = match.Groups[3].Value;
|
||||
if (string.IsNullOrEmpty(siteRelativePath))
|
||||
{
|
||||
siteRelativePath = "/";
|
||||
}
|
||||
|
||||
GraphServiceClient graphServiceClient = await _aadAuthenticationManager.GetGraphServiceClientAsync();
|
||||
Site site = await graphServiceClient.Sites.GetByPath(siteRelativePath, hostName).Request().GetAsync();
|
||||
ISiteDrivesCollectionPage drives = await graphServiceClient.Sites[site.Id].Drives.Request().GetAsync();
|
||||
|
||||
Drive drive = drives.SingleOrDefault(o => WebUtility.UrlDecode(o.WebUrl).Equals(docLibUrl, StringComparison.CurrentCultureIgnoreCase));
|
||||
if (drive == null)
|
||||
{
|
||||
throw new Exception("Drive not found");
|
||||
}
|
||||
|
||||
return graphServiceClient.Drives[drive.Id].RequestUrl;
|
||||
}
|
||||
|
||||
private async Task InitDriveAsync(string driveUrl)
|
||||
{
|
||||
try
|
||||
{
|
||||
string realDriveURL;
|
||||
if (driveUrl.StartsWith("https://graph.microsoft.com/", StringComparison.CurrentCultureIgnoreCase))
|
||||
{
|
||||
realDriveURL = driveUrl;
|
||||
}
|
||||
else
|
||||
{
|
||||
realDriveURL = await GetDriveUrlFromSharePointUrlAsync(driveUrl);
|
||||
}
|
||||
|
||||
GraphServiceClient graphServiceClient = await _aadAuthenticationManager.GetGraphServiceClientAsync();
|
||||
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, realDriveURL);
|
||||
await graphServiceClient.AuthenticationProvider.AuthenticateRequestAsync(message);
|
||||
|
||||
HttpResponseMessage result = await graphServiceClient.HttpProvider.SendAsync(message);
|
||||
if (result.StatusCode == HttpStatusCode.OK)
|
||||
{
|
||||
string json = await result.Content.ReadAsStringAsync();
|
||||
Drive drive = JsonConvert.DeserializeObject<Drive>(json);
|
||||
if (drive != null)
|
||||
{
|
||||
_driveId = drive.Id;
|
||||
_driveItemPath.Clear();
|
||||
DriveItem rootDriveItem = await graphServiceClient.Drives[_driveId].Root.Request().GetAsync();
|
||||
_driveItemPath.Push(rootDriveItem.Id);
|
||||
await LoadFilesAsync(rootDriveItem.Id);
|
||||
BackButtonVisibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadFilesAsync(string driveItemId, int pageIndex = 0)
|
||||
{
|
||||
IsDetailPaneVisible = false;
|
||||
HideDetailsPane();
|
||||
if (!string.IsNullOrEmpty(_driveId))
|
||||
{
|
||||
try
|
||||
{
|
||||
_cancelLoadFile.Cancel(false);
|
||||
_cancelLoadFile.Dispose();
|
||||
_cancelLoadFile = new CancellationTokenSource();
|
||||
_list.Items.Clear();
|
||||
VisualStateManager.GoToState(this, NavStatesFolderReadonly, false);
|
||||
QueryOption queryOption = new QueryOption("$top", PageSize.ToString());
|
||||
GraphServiceClient graphServiceClient = await _aadAuthenticationManager.GetGraphServiceClientAsync();
|
||||
Task<IDriveItemChildrenCollectionPage> taskFiles = graphServiceClient.Drives[_driveId].Items[driveItemId].Children.Request(new List<Option> { queryOption }).GetAsync(_cancelLoadFile.Token);
|
||||
IDriveItemChildrenCollectionPage files = await taskFiles;
|
||||
if (!taskFiles.IsCanceled)
|
||||
{
|
||||
_list.Items.Clear();
|
||||
foreach (DriveItem file in files)
|
||||
{
|
||||
_list.Items.Add(file);
|
||||
}
|
||||
|
||||
_nextPageRequest = files.NextPageRequest;
|
||||
HasMore = _nextPageRequest != null;
|
||||
VisualStateManager.GoToState(this, NavStatesFolderReadonly, false);
|
||||
if (_driveItemPath.Count > 1)
|
||||
{
|
||||
IDriveItemPermissionsCollectionPage permissions = await graphServiceClient.Drives[_driveId].Items[driveItemId].Permissions.Request().GetAsync();
|
||||
foreach (Permission permission in permissions)
|
||||
{
|
||||
if (permission.Roles.Contains("write") || permission.Roles.Contains("owner"))
|
||||
{
|
||||
VisualStateManager.GoToState(this, NavStatesFolderEdit, false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
VisualStateManager.GoToState(this, NavStatesFolderEdit, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (_list.Items.Count > 0)
|
||||
{
|
||||
_list.SelectedIndex = 0;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task LoadNextPageAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (_nextPageRequest != null)
|
||||
{
|
||||
Task<IDriveItemChildrenCollectionPage> taskItems = _nextPageRequest.GetAsync(_cancelLoadFile.Token);
|
||||
IDriveItemChildrenCollectionPage items = await taskItems;
|
||||
if (!taskItems.IsCanceled)
|
||||
{
|
||||
foreach (DriveItem item in items)
|
||||
{
|
||||
_list.Items.Add(item);
|
||||
}
|
||||
|
||||
_nextPageRequest = items.NextPageRequest;
|
||||
HasMore = _nextPageRequest != null;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
private void HideDetailsPane()
|
||||
{
|
||||
VisualStateManager.GoToState(this, DetailPaneStatesHide, false);
|
||||
if (_driveItemPath.Count <= 1)
|
||||
{
|
||||
BackButtonVisibility = Visibility.Collapsed;
|
||||
}
|
||||
}
|
||||
|
||||
private void ShowDetailsPane()
|
||||
{
|
||||
switch (DetailPane)
|
||||
{
|
||||
case DetailPaneDisplayMode.Side:
|
||||
if (_driveItemPath.Count <= 1)
|
||||
{
|
||||
BackButtonVisibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
VisualStateManager.GoToState(this, DetailPaneStatesSide, false);
|
||||
break;
|
||||
case DetailPaneDisplayMode.Bottom:
|
||||
if (_driveItemPath.Count <= 1)
|
||||
{
|
||||
BackButtonVisibility = Visibility.Collapsed;
|
||||
}
|
||||
|
||||
VisualStateManager.GoToState(this, DetailPaneStatesBottom, false);
|
||||
break;
|
||||
case DetailPaneDisplayMode.Full:
|
||||
BackButtonVisibility = Visibility.Visible;
|
||||
VisualStateManager.GoToState(this, DetailPaneStatesFull, false);
|
||||
break;
|
||||
default:
|
||||
HideDetailsPane();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,325 +0,0 @@
|
|||
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:local="using:Microsoft.Toolkit.Uwp.UI.Controls.Graph">
|
||||
|
||||
<local:DriveItemIconConverter x:Key="DriveItemIconConverter" />
|
||||
<local:FileSizeConverter x:Key="FileSizeConverter" />
|
||||
|
||||
<Style x:Name="MetaLabel"
|
||||
TargetType="TextBlock">
|
||||
<Setter Property="FontWeight" Value="Bold" />
|
||||
<Setter Property="Margin" Value="10,5,10,0" />
|
||||
</Style>
|
||||
<Style x:Name="MetaValue"
|
||||
TargetType="TextBlock">
|
||||
<Setter Property="Margin" Value="10,5" />
|
||||
</Style>
|
||||
<Style x:Name="MetaValueLink"
|
||||
TargetType="HyperlinkButton">
|
||||
<Setter Property="Margin" Value="10,5" />
|
||||
</Style>
|
||||
<Style x:Name="MetaValueProfile"
|
||||
TargetType="local:ProfileCard">
|
||||
<Setter Property="Margin" Value="10,5" />
|
||||
</Style>
|
||||
<Style x:Name="ToolbarButton"
|
||||
TargetType="Button">
|
||||
<Setter Property="Height" Value="48" />
|
||||
<Setter Property="Background" Value="Transparent" />
|
||||
</Style>
|
||||
<Style x:Name="ToolbarButtonImage"
|
||||
TargetType="Image">
|
||||
<Setter Property="Stretch" Value="Uniform" />
|
||||
</Style>
|
||||
<Style TargetType="local:SharePointFileList">
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="local:SharePointFileList">
|
||||
<Border>
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="60" />
|
||||
<RowDefinition Height="3*" />
|
||||
<RowDefinition Height="4*" />
|
||||
<RowDefinition Height="3*" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="3*" />
|
||||
<ColumnDefinition Width="4*" />
|
||||
<ColumnDefinition Width="3*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<StackPanel Grid.ColumnSpan="3"
|
||||
Margin="12,0,0,0"
|
||||
Orientation="Horizontal">
|
||||
<Button x:Name="back"
|
||||
AutomationProperties.Name="Back"
|
||||
Style="{StaticResource ToolbarButton}"
|
||||
Visibility="{TemplateBinding BackButtonVisibility}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<SymbolIcon Symbol="Back" />
|
||||
<TextBlock Margin="5,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="Back" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Name="upload"
|
||||
AutomationProperties.Name="Upload a new file"
|
||||
Style="{StaticResource ToolbarButton}"
|
||||
Visibility="Collapsed">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<SymbolIcon Symbol="Upload" />
|
||||
<TextBlock Margin="5,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="Upload" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Name="share"
|
||||
AutomationProperties.Name="Get share link"
|
||||
Style="{StaticResource ToolbarButton}"
|
||||
Visibility="Collapsed">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<SymbolIcon Symbol="Share" />
|
||||
<TextBlock Margin="5,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="Share" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Name="download"
|
||||
AutomationProperties.Name="Download selected file"
|
||||
Style="{StaticResource ToolbarButton}"
|
||||
Visibility="Collapsed">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<SymbolIcon Symbol="Download" />
|
||||
<TextBlock Margin="5,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="Download" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Name="delete"
|
||||
AutomationProperties.Name="Delete selected file"
|
||||
Style="{StaticResource ToolbarButton}"
|
||||
Visibility="Collapsed">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<SymbolIcon Symbol="Delete" />
|
||||
<TextBlock Margin="5,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="Delete" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
|
||||
<TextBlock Name="status"
|
||||
VerticalAlignment="Center"
|
||||
Text="{TemplateBinding StatusMessage}" />
|
||||
<HyperlinkButton Name="error"
|
||||
VerticalAlignment="Center"
|
||||
AutomationProperties.Name="Show error message"
|
||||
Content="Errors adding files."
|
||||
Visibility="Collapsed" />
|
||||
<Button Name="cancel"
|
||||
AutomationProperties.Name="Cancel uploading"
|
||||
Style="{StaticResource ToolbarButton}"
|
||||
Visibility="Collapsed">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<SymbolIcon Symbol="Cancel" />
|
||||
<TextBlock Margin="5,0,0,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="Cancel" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</StackPanel>
|
||||
<ListView x:Name="list"
|
||||
Grid.Row="1"
|
||||
Grid.RowSpan="3"
|
||||
Grid.ColumnSpan="3"
|
||||
AutomationProperties.Name="List"
|
||||
IsItemClickEnabled="True">
|
||||
<ListView.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<StackPanel Height="60"
|
||||
AutomationProperties.Name="{Binding Path=Name}"
|
||||
Orientation="Horizontal">
|
||||
<Image Width="32"
|
||||
Height="32"
|
||||
Margin="0,10,10,10"
|
||||
Source="{Binding Converter={StaticResource DriveItemIconConverter}}" />
|
||||
<TextBlock VerticalAlignment="Center"
|
||||
Text="{Binding Path=Name}" />
|
||||
</StackPanel>
|
||||
</DataTemplate>
|
||||
</ListView.ItemTemplate>
|
||||
<ListView.Footer>
|
||||
<Button x:Name="hasMore"
|
||||
Width="Auto"
|
||||
HorizontalAlignment="Stretch"
|
||||
AutomationProperties.Name="Load more items"
|
||||
BorderThickness="0"
|
||||
Style="{StaticResource ToolbarButton}"
|
||||
Visibility="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=HasMore}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Margin="0,0,5,0"
|
||||
VerticalAlignment="Center"
|
||||
Text="Load More" />
|
||||
<SymbolIcon Symbol="More" />
|
||||
</StackPanel>
|
||||
</Button>
|
||||
</ListView.Footer>
|
||||
</ListView>
|
||||
|
||||
<Grid x:Name="thumbnail"
|
||||
Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Padding="5"
|
||||
Background="{ThemeResource SystemBaseMediumColor}"
|
||||
Visibility="Collapsed">
|
||||
<Image Source="{TemplateBinding ThumbnailImageSource}" />
|
||||
</Grid>
|
||||
|
||||
<ScrollViewer x:Name="details"
|
||||
Background="{ThemeResource SystemBaseLowColor}"
|
||||
Visibility="Collapsed">
|
||||
<StackPanel>
|
||||
<TextBlock Style="{StaticResource MetaLabel}">Name</TextBlock>
|
||||
<HyperlinkButton NavigateUri="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=SelectedFile.WebUrl}"
|
||||
Style="{StaticResource MetaValueLink}">
|
||||
<TextBlock Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=SelectedFile.Name}"
|
||||
TextWrapping="Wrap" />
|
||||
</HyperlinkButton>
|
||||
<TextBlock Style="{StaticResource MetaLabel}">Size</TextBlock>
|
||||
<TextBlock Style="{StaticResource MetaValue}"
|
||||
Text="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=FileSize, Converter={StaticResource FileSizeConverter}}" />
|
||||
<TextBlock Style="{StaticResource MetaLabel}">Last Modified</TextBlock>
|
||||
<TextBlock Style="{StaticResource MetaValue}"
|
||||
Text="{TemplateBinding LastModified}" />
|
||||
<TextBlock Style="{StaticResource MetaLabel}">Last Modified By</TextBlock>
|
||||
<local:ProfileCard DisplayMode="LargeProfilePhotoLeft"
|
||||
Style="{StaticResource MetaValueProfile}"
|
||||
UserId="{Binding RelativeSource={RelativeSource Mode=TemplatedParent}, Path=SelectedFile.LastModifiedBy.User.Id}" />
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
<VisualStateManager.VisualStateGroups>
|
||||
<VisualStateGroup x:Name="NavStates">
|
||||
<VisualState x:Name="FolderReadonly">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="upload.Visibility" Value="Collapsed" />
|
||||
<Setter Target="share.Visibility" Value="Collapsed" />
|
||||
<Setter Target="download.Visibility" Value="Collapsed" />
|
||||
<Setter Target="delete.Visibility" Value="Collapsed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="FolderEdit">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="upload.Visibility" Value="Visible" />
|
||||
<Setter Target="share.Visibility" Value="Collapsed" />
|
||||
<Setter Target="download.Visibility" Value="Collapsed" />
|
||||
<Setter Target="delete.Visibility" Value="Collapsed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="FileReadonly">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="share.Visibility" Value="Collapsed" />
|
||||
<Setter Target="download.Visibility" Value="Visible" />
|
||||
<Setter Target="delete.Visibility" Value="Collapsed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="FileEdit">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="share.Visibility" Value="Visible" />
|
||||
<Setter Target="download.Visibility" Value="Visible" />
|
||||
<Setter Target="delete.Visibility" Value="Visible" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="UploadStatus">
|
||||
<VisualState x:Name="NotUploading">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="status.Visibility" Value="Collapsed" />
|
||||
<Setter Target="error.Visibility" Value="Collapsed" />
|
||||
<Setter Target="cancel.Visibility" Value="Collapsed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Uploading">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="status.Visibility" Value="Visible" />
|
||||
<Setter Target="error.Visibility" Value="Collapsed" />
|
||||
<Setter Target="cancel.Visibility" Value="Visible" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Error">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="status.Visibility" Value="Collapsed" />
|
||||
<Setter Target="error.Visibility" Value="Visible" />
|
||||
<Setter Target="cancel.Visibility" Value="Collapsed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
<VisualStateGroup x:Name="DetailPaneStates">
|
||||
<VisualState x:Name="Hide">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="list.Visibility" Value="Visible" />
|
||||
<Setter Target="list.(Grid.RowSpan)" Value="3" />
|
||||
<Setter Target="list.(Grid.ColumnSpan)" Value="3" />
|
||||
<Setter Target="thumbnail.Visibility" Value="Collapsed" />
|
||||
<Setter Target="details.Visibility" Value="Collapsed" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Side">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="list.Visibility" Value="Visible" />
|
||||
<Setter Target="list.(Grid.RowSpan)" Value="3" />
|
||||
<Setter Target="list.(Grid.ColumnSpan)" Value="2" />
|
||||
<Setter Target="thumbnail.Visibility" Value="Visible" />
|
||||
<Setter Target="thumbnail.(Grid.Row)" Value="1" />
|
||||
<Setter Target="thumbnail.(Grid.RowSpan)" Value="1" />
|
||||
<Setter Target="thumbnail.(Grid.Column)" Value="2" />
|
||||
<Setter Target="thumbnail.(Grid.ColumnSpan)" Value="1" />
|
||||
<Setter Target="details.Visibility" Value="Visible" />
|
||||
<Setter Target="details.(Grid.Row)" Value="2" />
|
||||
<Setter Target="details.(Grid.RowSpan)" Value="2" />
|
||||
<Setter Target="details.(Grid.Column)" Value="2" />
|
||||
<Setter Target="details.(Grid.ColumnSpan)" Value="1" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Bottom">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="list.Visibility" Value="Visible" />
|
||||
<Setter Target="list.(Grid.RowSpan)" Value="2" />
|
||||
<Setter Target="list.(Grid.ColumnSpan)" Value="3" />
|
||||
<Setter Target="thumbnail.Visibility" Value="Visible" />
|
||||
<Setter Target="thumbnail.(Grid.Row)" Value="3" />
|
||||
<Setter Target="thumbnail.(Grid.RowSpan)" Value="1" />
|
||||
<Setter Target="thumbnail.(Grid.Column)" Value="0" />
|
||||
<Setter Target="thumbnail.(Grid.ColumnSpan)" Value="1" />
|
||||
<Setter Target="details.Visibility" Value="Visible" />
|
||||
<Setter Target="details.(Grid.Row)" Value="3" />
|
||||
<Setter Target="details.(Grid.RowSpan)" Value="1" />
|
||||
<Setter Target="details.(Grid.Column)" Value="1" />
|
||||
<Setter Target="details.(Grid.ColumnSpan)" Value="2" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
<VisualState x:Name="Full">
|
||||
<VisualState.Setters>
|
||||
<Setter Target="list.Visibility" Value="Collapsed" />
|
||||
<Setter Target="thumbnail.Visibility" Value="Visible" />
|
||||
<Setter Target="thumbnail.(Grid.Row)" Value="1" />
|
||||
<Setter Target="thumbnail.(Grid.RowSpan)" Value="3" />
|
||||
<Setter Target="thumbnail.(Grid.Column)" Value="0" />
|
||||
<Setter Target="thumbnail.(Grid.ColumnSpan)" Value="1" />
|
||||
<Setter Target="details.Visibility" Value="Visible" />
|
||||
<Setter Target="details.(Grid.Row)" Value="1" />
|
||||
<Setter Target="details.(Grid.RowSpan)" Value="3" />
|
||||
<Setter Target="details.(Grid.Column)" Value="1" />
|
||||
<Setter Target="details.(Grid.ColumnSpan)" Value="2" />
|
||||
</VisualState.Setters>
|
||||
</VisualState>
|
||||
</VisualStateGroup>
|
||||
</VisualStateManager.VisualStateGroups>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</ResourceDictionary>
|
|
@ -22,9 +22,6 @@ EndProject
|
|||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Toolkit.Uwp.Services", "Microsoft.Toolkit.Uwp.Services\Microsoft.Toolkit.Uwp.Services.csproj", "{7189A42D-6F1A-4FA3-8E00-E2C14FDF167A}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Toolkit.Uwp.UI.Controls", "Microsoft.Toolkit.Uwp.UI.Controls\Microsoft.Toolkit.Uwp.UI.Controls.csproj", "{E9FAABFB-D726-42C1-83C1-CB46A29FEA81}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{34398053-FC70-4243-84F9-F355DEFFF66D} = {34398053-FC70-4243-84F9-F355DEFFF66D}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Notifications", "Notifications", "{9333C63A-F64F-4797-82B3-017422668A5D}"
|
||||
EndProject
|
||||
|
@ -91,6 +88,10 @@ EndProject
|
|||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GazeInputTest", "GazeInputTest\GazeInputTest.csproj", "{A122EA02-4DE7-413D-BFBF-AF7DFC668DD6}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Toolkit.Uwp.UI.Controls.Graph", "Microsoft.Toolkit.Uwp.UI.Controls.Graph\Microsoft.Toolkit.Uwp.UI.Controls.Graph.csproj", "{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{34398053-FC70-4243-84F9-F355DEFFF66D} = {34398053-FC70-4243-84F9-F355DEFFF66D}
|
||||
{3DD8AA7C-3569-4E51-992F-0C2257E8878E} = {3DD8AA7C-3569-4E51-992F-0C2257E8878E}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SharedMSBuildProjectFiles) = preSolution
|
||||
|
@ -686,13 +687,9 @@ Global
|
|||
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Debug|x86.Build.0 = Debug|Any CPU
|
||||
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Native|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Native|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Native|ARM.ActiveCfg = Debug|Any CPU
|
||||
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Native|ARM.Build.0 = Debug|Any CPU
|
||||
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Native|x64.ActiveCfg = Debug|Any CPU
|
||||
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Native|x64.Build.0 = Debug|Any CPU
|
||||
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Native|x86.ActiveCfg = Debug|Any CPU
|
||||
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Native|x86.Build.0 = Debug|Any CPU
|
||||
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{D4D78CBA-B238-4794-89A0-4F1A2D8FEA97}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||
|
|
Загрузка…
Ссылка в новой задаче