Skip to content

Commit

Permalink
⭐Mobile App - process autologin (#1202)
Browse files Browse the repository at this point in the history
* handle confirmation email autologin token

* do not display error that login page close unexpectedly after autologin

* App.xaml.cs - remove InvokeOnMainThreadAsync

rename method

* added InitializeMainPage extension method
  • Loading branch information
vladislav-kir authored Feb 24, 2025
1 parent 9778bc4 commit 46a8b2c
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 22 deletions.
16 changes: 16 additions & 0 deletions src/MobileUI/Common/ApplicationExtension.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
namespace SSW.Rewards.Mobile.Common;
public static class ApplicationExtension
{
public static async Task InitializeMainPage(this Application application)
{
if (!(application.MainPage is AppShell))
{
await MainThread.InvokeOnMainThreadAsync(() =>
{
application.MainPage = new AppShell();
});
}

await Shell.Current.GoToAsync("//main");
}
}
36 changes: 22 additions & 14 deletions src/MobileUI/Features/App.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,24 +45,32 @@ protected override async void OnAppLinkRequestReceived(Uri uri)
{
base.OnAppLinkRequestReceived(uri);

if (uri.Scheme != ApiClientConstants.RewardsQRCodeProtocol)
if (uri.Scheme == ApiClientConstants.RewardsQRCodeProtocol)
{
return;
}

var queryDictionary = System.Web.HttpUtility.ParseQueryString(uri.Query);
var code = queryDictionary.Get(ApiClientConstants.RewardsQRCodeProtocolQueryName);
var queryDictionary = System.Web.HttpUtility.ParseQueryString(uri.Query);
var code = queryDictionary.Get(ApiClientConstants.RewardsQRCodeProtocolQueryName);

if (_authService.IsLoggedIn)
{
var vm = ActivatorUtilities.CreateInstance<ScanResultViewModel>(_provider);
var popup = new PopupPages.ScanResult(vm, code);
await MopupService.Instance.PushAsync(popup);
if (_authService.IsLoggedIn)
{
var vm = ActivatorUtilities.CreateInstance<ScanResultViewModel>(_provider);
var popup = new PopupPages.ScanResult(vm, code);
await MopupService.Instance.PushAsync(popup);
}
else
{
((LoginPage)MainPage)?.QueueCodeScan(code);
}
}
else
else if ($"{uri.Scheme}://{uri.Host}" == Constants.AuthRedirectUrl)
{
((LoginPage)MainPage)?.QueueCodeScan(code);
}
var queryDictionary = System.Web.HttpUtility.ParseQueryString(uri.Query);
var token = queryDictionary.Get("token");

if (!string.IsNullOrEmpty(token))
{
await _authService.AutologinAsync(token);
}
}
}

private async Task CheckApiCompatibilityAsync()
Expand Down
15 changes: 11 additions & 4 deletions src/MobileUI/Features/Login/LoginPageViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using CommunityToolkit.Mvvm.Input;
using Microsoft.AppCenter.Crashes;
using Mopups.Services;
using SSW.Rewards.Mobile.Common;

namespace SSW.Rewards.Mobile.ViewModels;

Expand Down Expand Up @@ -65,8 +66,14 @@ private async Task LoginTapped()
if (status != ApiStatus.Success)
{
await WaitForWindowClose();
var alert = statusAlerts.GetValueOrDefault(status, (Title: "Unexpected Error", Message: "Something went wrong there, please try again later."));
await App.Current.MainPage.DisplayAlert(alert.Title, alert.Message, "OK");

// Only display error if user is not logged in.
// Autologin will fall here, if login page is opened, despite being successfull.
if (_authService.IsLoggedIn && _authService.HasCachedAccount)
{
var alert = statusAlerts.GetValueOrDefault(status, (Title: "Unexpected Error", Message: "Something went wrong there, please try again later."));
await App.Current.MainPage.DisplayAlert(alert.Title, alert.Message, "OK");
}
}
else
{
Expand Down Expand Up @@ -130,8 +137,8 @@ await Application.Current.MainPage.DisplayAlert("Login Failure",

private async Task OnAfterLogin()
{
Application.Current.MainPage = new AppShell();
await Shell.Current.GoToAsync("//main");
await Application.Current.InitializeMainPage();

var granted = await _permissionsService.CheckAndRequestPermission<Permissions.PostNotifications>();
if (granted)
{
Expand Down
4 changes: 0 additions & 4 deletions src/MobileUI/Platforms/Android/MainActivity.cs
Original file line number Diff line number Diff line change
@@ -1,11 +1,7 @@
using Android.App;
using Android.Content.PM;
using Android.Gms.Extensions;
using Android.OS;
using Firebase.Messaging;
using Microsoft.Maui.Controls.Compatibility.Platform.Android;
using Microsoft.Maui.Controls.PlatformConfiguration;
using SSW.Rewards.Mobile.Platforms.Android;
using Color = Microsoft.Maui.Graphics.Color;

namespace SSW.Rewards.Mobile;
Expand Down
41 changes: 41 additions & 0 deletions src/MobileUI/Services/AuthenticationService.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
using System.IdentityModel.Tokens.Jwt;
using IdentityModel.Client;
using IdentityModel.OidcClient;
using IdentityModel.OidcClient.Results;
using Microsoft.AppCenter.Crashes;
using SSW.Rewards.Mobile.Common;
using IBrowser = IdentityModel.OidcClient.Browser.IBrowser;

namespace SSW.Rewards.Mobile.Services;

public interface IAuthenticationService
{
Task AutologinAsync(string accessToken);
Task<ApiStatus> SignInAsync();
Task<string> GetAccessToken();
Task SignOut();
Expand Down Expand Up @@ -42,6 +45,44 @@ public AuthenticationService(IBrowser browser)
};
}

public async Task AutologinAsync(string accessToken)
{
try
{
var tokenHandler = new JwtSecurityTokenHandler();
var jwtToken = tokenHandler.ReadJwtToken(accessToken);

_accessToken = accessToken;
_tokenExpiry = jwtToken.ValidTo;

try
{
Preferences.Set(nameof(HasCachedAccount), true);
DetailsUpdated?.Invoke(this, EventArgs.Empty);

await Application.Current.InitializeMainPage();
}
catch (Exception ex)
{
Crashes.TrackError(new Exception("Failed to set a logged-in state"));

// TECH DEBT: Workaround for iOS since calling DisplayAlert while a Safari web view is in
// the process of closing causes the alert to never appear and the await call never returns.
if (DeviceInfo.Platform == DevicePlatform.iOS)
{
await Task.Delay(1000);
}

await App.Current.MainPage.DisplayAlert("Login Failure", "There seems to have been a problem logging you in. Please try again.", "OK");
}
}
catch (Exception ex)
{
Crashes.TrackError(new Exception($"AuthDebug: unknown exception was thrown during SignIn ${ex.Message}; ${ex.StackTrace}"));
await SignOut();
}
}

public async Task<ApiStatus> SignInAsync()
{
try
Expand Down

0 comments on commit 46a8b2c

Please sign in to comment.