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());
+ });
+ }
}
}