diff --git a/src/App/Pages/Accounts/LoginPage.xaml b/src/App/Pages/Accounts/LoginPage.xaml index 99fefed16..a0a8d9bea 100644 --- a/src/App/Pages/Accounts/LoginPage.xaml +++ b/src/App/Pages/Accounts/LoginPage.xaml @@ -1,5 +1,5 @@  - @@ -49,6 +50,7 @@ Grid.Row="0" Grid.Column="0" /> - + diff --git a/src/App/Pages/Accounts/LoginPage.xaml.cs b/src/App/Pages/Accounts/LoginPage.xaml.cs index 97644a85e..67ed7af93 100644 --- a/src/App/Pages/Accounts/LoginPage.xaml.cs +++ b/src/App/Pages/Accounts/LoginPage.xaml.cs @@ -1,14 +1,9 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using Xamarin.Forms; -using Xamarin.Forms.Xaml; namespace Bit.App.Pages { - public partial class LoginPage : ContentPage + public partial class LoginPage : BaseContentPage { private LoginPageViewModel _vm; @@ -17,6 +12,23 @@ namespace Bit.App.Pages InitializeComponent(); _vm = BindingContext as LoginPageViewModel; _vm.Page = this; + MasterPasswordEntry = _masterPassword; + } + + public Entry MasterPasswordEntry { get; set; } + + protected override async void OnAppearing() + { + base.OnAppearing(); + await _vm.InitAsync(); + if(string.IsNullOrWhiteSpace(_vm.Email)) + { + RequestFocus(_email); + } + else + { + RequestFocus(_masterPassword); + } } private async void LogIn_Clicked(object sender, EventArgs e) diff --git a/src/App/Pages/Accounts/LoginPageViewModel.cs b/src/App/Pages/Accounts/LoginPageViewModel.cs index 652baa339..d5ecf031d 100644 --- a/src/App/Pages/Accounts/LoginPageViewModel.cs +++ b/src/App/Pages/Accounts/LoginPageViewModel.cs @@ -10,9 +10,13 @@ namespace Bit.App.Pages { public class LoginPageViewModel : BaseViewModel { + private const string Keys_RememberedEmail = "rememberedEmail"; + private const string Keys_RememberEmail = "rememberEmail"; + private readonly IDeviceActionService _deviceActionService; private readonly IAuthService _authService; private readonly ISyncService _syncService; + private readonly IStorageService _storageService; private bool _showPassword; @@ -21,6 +25,7 @@ namespace Bit.App.Pages _deviceActionService = ServiceContainer.Resolve("deviceActionService"); _authService = ServiceContainer.Resolve("authService"); _syncService = ServiceContainer.Resolve("syncService"); + _storageService = ServiceContainer.Resolve("storageService"); PageTitle = AppResources.Bitwarden; TogglePasswordCommand = new Command(TogglePassword); @@ -40,6 +45,17 @@ namespace Bit.App.Pages public string ShowPasswordIcon => ShowPassword ? "" : ""; public string Email { get; set; } public string MasterPassword { get; set; } + public bool RememberEmail { get; set; } + + public async Task InitAsync() + { + if(string.IsNullOrWhiteSpace(Email)) + { + Email = await _storageService.GetAsync(Keys_RememberedEmail); + } + var rememberEmail = await _storageService.GetAsync(Keys_RememberEmail); + RememberEmail = rememberEmail.GetValueOrDefault(true); + } public async Task LogInAsync() { @@ -68,7 +84,14 @@ namespace Bit.App.Pages await _deviceActionService.ShowLoadingAsync(AppResources.LoggingIn); var response = await _authService.LogInAsync(Email, MasterPassword); await _deviceActionService.HideLoadingAsync(); - // TODO: remember email? + if(RememberEmail) + { + await _storageService.SaveAsync(Keys_RememberedEmail, Email); + } + else + { + await _storageService.RemoveAsync(Keys_RememberedEmail); + } if(response.TwoFactor) { // TODO: 2fa page @@ -89,6 +112,7 @@ namespace Bit.App.Pages public void TogglePassword() { ShowPassword = !ShowPassword; + (Page as LoginPage).MasterPasswordEntry.Focus(); } } } diff --git a/src/App/Pages/BaseContentPage.cs b/src/App/Pages/BaseContentPage.cs index dce78688b..be09802e3 100644 --- a/src/App/Pages/BaseContentPage.cs +++ b/src/App/Pages/BaseContentPage.cs @@ -6,6 +6,8 @@ namespace Bit.App.Pages { public class BaseContentPage : ContentPage { + protected int AndroidShowModalAnimationDelay = 400; + protected void SetActivityIndicator() { Content = new ActivityIndicator @@ -33,9 +35,23 @@ namespace Bit.App.Pages } await Task.Run(async () => { - await Task.Delay(400); + await Task.Delay(AndroidShowModalAnimationDelay); Device.BeginInvokeOnMainThread(async () => await DoWorkAsync()); }); } + + protected void RequestFocus(Entry entry) + { + if(Device.RuntimePlatform == Device.iOS) + { + entry.Focus(); + return; + } + Task.Run(async () => + { + await Task.Delay(AndroidShowModalAnimationDelay); + Device.BeginInvokeOnMainThread(() => entry.Focus()); + }); + } } }