From 800f78703a0256baeeec3d08cd7606ca8400d1c3 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Fri, 11 Jun 2021 12:04:16 -0700 Subject: [PATCH 1/3] Updated LoginButton events to fire Login/Logout Completed events in response to the GlobalProvider --- .../LoginButton/LoginButton.Properties.cs | 2 +- .../Controls/LoginButton/LoginButton.cs | 74 +++++++++---------- 2 files changed, 38 insertions(+), 38 deletions(-) diff --git a/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.Properties.cs b/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.Properties.cs index addd2f8..dbe8764 100644 --- a/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.Properties.cs +++ b/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.Properties.cs @@ -18,7 +18,7 @@ public partial class LoginButton public User UserDetails { get { return (User)GetValue(UserDetailsProperty); } - set { SetValue(UserDetailsProperty, value); } + protected set { SetValue(UserDetailsProperty, value); } } /// diff --git a/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.cs b/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.cs index 05b01c8..b7c706a 100644 --- a/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.cs +++ b/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.cs @@ -34,6 +34,7 @@ public LoginButton() { this.DefaultStyleKey = typeof(LoginButton); + ProviderManager.Instance.ProviderUpdated += (sender, args) => LoadData(); ProviderManager.Instance.ProviderStateChanged += (sender, args) => LoadData(); } @@ -102,38 +103,44 @@ private async void LoadData() if (provider == null) { + UserDetails = null; return; } - if (provider.State == ProviderState.Loading) + switch (provider.State) { - IsLoading = true; - } - else if (provider.State == ProviderState.SignedIn) - { - try - { - // https://github.com/microsoftgraph/microsoft-graph-toolkit/blob/master/src/components/mgt-login/mgt-login.ts#L139 - // TODO: Batch with photo request later? https://github.com/microsoftgraph/msgraph-sdk-dotnet-core/issues/29 - UserDetails = await provider.GetClient().GetMeAsync(); - } - catch (Exception e) - { - LoginFailed?.Invoke(this, new LoginFailedEventArgs(e)); - } + case ProviderState.Loading: + IsLoading = true; + break; - IsLoading = false; - } - else if (provider.State == ProviderState.SignedOut) - { - UserDetails = null; // What if this was user provided? Should we not hook into these events then? + case ProviderState.SignedIn: + try + { + // https://github.com/microsoftgraph/microsoft-graph-toolkit/blob/master/src/components/mgt-login/mgt-login.ts#L139 + // TODO: Batch with photo request later? https://github.com/microsoftgraph/msgraph-sdk-dotnet-core/issues/29 + UserDetails = await provider.GetClient().GetMeAsync(); - IsLoading = false; - } - else - { - // Provider in Loading state - Debug.Fail("unsupported state"); + LoginCompleted?.Invoke(this, new EventArgs()); + } + catch (Exception e) + { + LoginFailed?.Invoke(this, new LoginFailedEventArgs(e)); + } + + IsLoading = false; + break; + + case ProviderState.SignedOut: + UserDetails = null; + LogoutCompleted?.Invoke(this, new EventArgs()); + + IsLoading = false; + break; + + default: + // Provider in Loading state + Debug.Fail("unsupported state"); + break; } } @@ -157,17 +164,12 @@ public async Task SignInAsync() IsLoading = true; await provider.SignInAsync(); - if (provider.State == ProviderState.SignedIn) + if (provider.State != ProviderState.SignedIn) { - // TODO: include user details? - LoginCompleted?.Invoke(this, new EventArgs()); - - LoadData(); - } - else - { - LoginFailed?.Invoke(this, new LoginFailedEventArgs(new TimeoutException("Login did not complete."))); + throw new TimeoutException("Login did not complete."); } + + LoadData(); } catch (Exception e) { @@ -221,8 +223,6 @@ public async Task SignOutAsync() IsLoading = true; await provider.SignOutAsync(); IsLoading = false; - - LogoutCompleted?.Invoke(this, new EventArgs()); } } } From 6c2ca9f63d3500e35fbc09f1d0b31b098eebe115 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Tue, 29 Jun 2021 12:39:59 -0700 Subject: [PATCH 2/3] Refactored LoginButton.cs to accomodate for new event pattern --- .../Controls/LoginButton/LoginButton.cs | 278 +++++++++++------- .../Controls/LoginButton/LoginButton.xaml | 2 +- 2 files changed, 172 insertions(+), 108 deletions(-) diff --git a/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.cs b/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.cs index 44134ef..98bd742 100644 --- a/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.cs +++ b/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.cs @@ -17,14 +17,14 @@ namespace CommunityToolkit.Graph.Uwp.Controls /// The control is a button which can be used to sign the user in or show them profile details. /// [TemplatePart(Name = LoginButtonPart, Type = typeof(Button))] - [TemplatePart(Name = SignOutButtonPart, Type = typeof(ButtonBase))] + [TemplatePart(Name = LogoutButtonPart, Type = typeof(ButtonBase))] public partial class LoginButton : Control { private const string LoginButtonPart = "PART_LoginButton"; - private const string SignOutButtonPart = "PART_SignOutButton"; + private const string LogoutButtonPart = "PART_LogoutButton"; private Button _loginButton; - private ButtonBase _signOutButton; + private ButtonBase _logoutButton; private bool _isLoading; @@ -48,18 +48,88 @@ public LoginButton() { this.DefaultStyleKey = typeof(LoginButton); - ProviderManager.Instance.ProviderUpdated += (sender, args) => LoadData(); - ProviderManager.Instance.ProviderStateChanged += (sender, args) => LoadData(); + ProviderManager.Instance.ProviderUpdated += OnProviderUpdated; + ProviderManager.Instance.ProviderStateChanged += OnProviderStateChanged; } /// - /// Update the enablement state of the button in relation to the _isLoading property. + /// Initiates logging in with the current registered in the . /// - protected void UpdateButtonEnablement() + /// A representing the asynchronous operation. + public async Task SignInAsync() { - if (_loginButton != null) + if (IsLoading) { - _loginButton.IsEnabled = !_isLoading; + return; + } + + var provider = ProviderManager.Instance.GlobalProvider; + if (provider != null) + { + try + { + IsLoading = true; + + var cargs = new CancelEventArgs(); + LoginInitiated?.Invoke(this, cargs); + if (cargs.Cancel) + { + IsLoading = false; + throw new OperationCanceledException(); + } + + await provider.SignInAsync(); + + if (provider.State != ProviderState.SignedIn) + { + throw new Exception("Login did not complete."); + } + } + catch (Exception e) + { + IsLoading = false; + LoginFailed?.Invoke(this, new LoginFailedEventArgs(e)); + } + } + } + + /// + /// Log a signed-in user out. + /// + /// A representing the asynchronous operation. + public async Task SignOutAsync() + { + if (IsLoading) + { + return; + } + + IsLoading = true; + + var cargs = new CancelEventArgs(); + LogoutInitiated?.Invoke(this, cargs); + if (cargs.Cancel) + { + return; + } + + var provider = ProviderManager.Instance.GlobalProvider; + if (provider != null) + { + try + { + await provider.SignOutAsync(); + + if (provider.State != ProviderState.SignedOut) + { + throw new Exception("Logout did not complete."); + } + } + catch + { + // There is no LogoutFailed event, so we do nothing. + IsLoading = false; + } } } @@ -80,161 +150,155 @@ protected override void OnApplyTemplate() _loginButton.Click += LoginButton_Click; } - if (_signOutButton != null) + if (_logoutButton != null) { - _signOutButton.Click -= LoginButton_Click; + _logoutButton.Click -= LogoutButton_Click; } - _signOutButton = GetTemplateChild(SignOutButtonPart) as ButtonBase; + _logoutButton = GetTemplateChild(LogoutButtonPart) as ButtonBase; - if (_signOutButton != null) + if (_logoutButton != null) { - _signOutButton.Click += SignOutButton_Click; + _logoutButton.Click += LogoutButton_Click; } LoadData(); } - private async void LoginButton_Click(object sender, RoutedEventArgs e) + /// + /// Show the user details flyout. + /// + protected void ShowFlyout() { - if (this.UserDetails != null) + if (FlyoutBase.GetAttachedFlyout(_loginButton) is FlyoutBase flyout) { - if (FlyoutBase.GetAttachedFlyout(_loginButton) is FlyoutBase flyout) - { - flyout.ShowAt(_loginButton); - } + flyout.ShowAt(_loginButton); } - else + } + + /// + /// Hide the user details flyout. + /// + protected void HideFlyout() + { + if (FlyoutBase.GetAttachedFlyout(_loginButton) is FlyoutBase flyout) { - var cargs = new CancelEventArgs(); - LoginInitiated?.Invoke(this, cargs); + flyout.Hide(); + } + } - if (!cargs.Cancel) - { - await SignInAsync(); - } + /// + /// Update the enablement state of the button in relation to the _isLoading property. + /// + protected void UpdateButtonEnablement() + { + if (_loginButton != null) + { + _loginButton.IsEnabled = !_isLoading; } } - private async void SignOutButton_Click(object sender, RoutedEventArgs e) + private void OnProviderUpdated(object sender, IProvider e) { - await SignOutAsync(); + if (e == null) + { + ClearUserDetails(); + } } - private async void LoadData() + private async void OnProviderStateChanged(object sender, ProviderStateChangedEventArgs e) { var provider = ProviderManager.Instance.GlobalProvider; - switch (provider?.State) + switch (provider.State) { + case ProviderState.SignedIn: + IsLoading = true; + await SetUserDetails(); + IsLoading = false; + LoginCompleted?.Invoke(this, new EventArgs()); + break; + + case ProviderState.SignedOut: + ClearUserDetails(); + IsLoading = false; + LogoutCompleted?.Invoke(this, new EventArgs()); + break; + case ProviderState.Loading: IsLoading = true; break; + } + } + private async void LoginButton_Click(object sender, RoutedEventArgs e) + { + var provider = ProviderManager.Instance.GlobalProvider; + switch (provider.State) + { case ProviderState.SignedIn: - try - { - IsLoading = true; - - // https://github.com/microsoftgraph/microsoft-graph-toolkit/blob/master/src/components/mgt-login/mgt-login.ts#L139 - // TODO: Batch with photo request later? https://github.com/microsoftgraph/msgraph-sdk-dotnet-core/issues/29 - UserDetails = await provider.GetClient().GetMeAsync(); - } - catch (Exception e) - { - LoginFailed?.Invoke(this, new LoginFailedEventArgs(e)); - } - - IsLoading = false; + ShowFlyout(); break; case ProviderState.SignedOut: - default: - UserDetails = null; // What if this was user provided? Should we not hook into these events then? - IsLoading = false; + await SignInAsync(); break; } } - /// - /// Initiates logging in with the current registered in the . - /// - /// A representing the asynchronous operation. - public async Task SignInAsync() + private async void LogoutButton_Click(object sender, RoutedEventArgs e) + { + HideFlyout(); + await SignOutAsync(); + } + + private async void LoadData() { - if (UserDetails != null || IsLoading) + if (IsLoading) { return; } var provider = ProviderManager.Instance.GlobalProvider; - - if (provider != null) + switch (provider?.State) { - try - { + case ProviderState.Loading: IsLoading = true; - await provider.SignInAsync(); + break; - if (provider.State != ProviderState.SignedIn) + case ProviderState.SignedIn: + if (UserDetails == null) { - throw new TimeoutException("Login did not complete."); + await SignInAsync(); } - LoadData(); - } - catch (Exception e) - { - LoginFailed?.Invoke(this, new LoginFailedEventArgs(e)); - } - finally - { IsLoading = false; - } - } - } - - /// - /// Log a signed-in user out. - /// - /// A representing the asynchronous operation. - public async Task SignOutAsync() - { - // Close Menu - if (FlyoutBase.GetAttachedFlyout(_loginButton) is FlyoutBase flyout) - { - flyout.Hide(); - } - - if (IsLoading) - { - return; - } - - var cargs = new CancelEventArgs(); - LogoutInitiated?.Invoke(this, cargs); + break; - if (cargs.Cancel) - { - return; - } + case ProviderState.SignedOut: + if (UserDetails != null) + { + await SignOutAsync(); + } - if (UserDetails != null) - { - UserDetails = null; - } - else - { - return; // No-op + IsLoading = false; + break; } + } + private async Task SetUserDetails() + { var provider = ProviderManager.Instance.GlobalProvider; - if (provider != null) { - IsLoading = true; - await provider.SignOutAsync(); - IsLoading = false; + // https://github.com/microsoftgraph/microsoft-graph-toolkit/blob/master/src/components/mgt-login/mgt-login.ts#L139 + // TODO: Batch with photo request later? https://github.com/microsoftgraph/msgraph-sdk-dotnet-core/issues/29 + UserDetails = await provider.GetClient().GetMeAsync(); } } + + private void ClearUserDetails() + { + UserDetails = null; + } } } diff --git a/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.xaml b/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.xaml index acbae71..eb5e6fb 100644 --- a/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.xaml +++ b/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.xaml @@ -45,7 +45,7 @@ - + From 7d5bdde19647f84a66088070d7098790fdb187f8 Mon Sep 17 00:00:00 2001 From: Shane Weaver Date: Mon, 12 Jul 2021 16:02:07 -0700 Subject: [PATCH 3/3] Removed unecessary IsLoading set --- CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.cs b/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.cs index 98bd742..991d6fa 100644 --- a/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.cs +++ b/CommunityToolkit.Graph.Uwp/Controls/LoginButton/LoginButton.cs @@ -74,7 +74,6 @@ public async Task SignInAsync() LoginInitiated?.Invoke(this, cargs); if (cargs.Cancel) { - IsLoading = false; throw new OperationCanceledException(); } @@ -125,7 +124,7 @@ public async Task SignOutAsync() throw new Exception("Logout did not complete."); } } - catch + finally { // There is no LogoutFailed event, so we do nothing. IsLoading = false;