diff --git a/src/App/App.csproj b/src/App/App.csproj index 22b8d6d73..c08fb2a9a 100644 --- a/src/App/App.csproj +++ b/src/App/App.csproj @@ -21,6 +21,9 @@ + + LoginPage.xaml + GeneratorPage.xaml @@ -37,7 +40,6 @@ - diff --git a/src/App/App.xaml.cs b/src/App/App.xaml.cs index 384c57bbe..6868a96e4 100644 --- a/src/App/App.xaml.cs +++ b/src/App/App.xaml.cs @@ -16,11 +16,13 @@ namespace Bit.App public partial class App : Application { private readonly MobileI18nService _i18nService; + private readonly IUserService _userService; private readonly IBroadcasterService _broadcasterService; private readonly IMessagingService _messagingService; public App() { + _userService = ServiceContainer.Resolve("userService"); _broadcasterService = ServiceContainer.Resolve("broadcasterService"); _messagingService = ServiceContainer.Resolve("messagingService"); _i18nService = ServiceContainer.Resolve("i18nService") as MobileI18nService; @@ -29,6 +31,17 @@ namespace Bit.App SetCulture(); ThemeManager.SetTheme("light"); MainPage = new HomePage(); + _userService.IsAuthenticatedAsync().ContinueWith(async authed => + { + if(await authed) + { + Current.MainPage = new TabsPage(); + } + else + { + Current.MainPage = new HomePage(); + } + }); ServiceContainer.Resolve("platformUtilsService").Init(); _broadcasterService.Subscribe("showDialog", async (details) => diff --git a/src/App/Pages/Accounts/LoginPage.xaml b/src/App/Pages/Accounts/LoginPage.xaml new file mode 100644 index 000000000..933622a7c --- /dev/null +++ b/src/App/Pages/Accounts/LoginPage.xaml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/src/App/Pages/Accounts/LoginPage.xaml.cs b/src/App/Pages/Accounts/LoginPage.xaml.cs new file mode 100644 index 000000000..97644a85e --- /dev/null +++ b/src/App/Pages/Accounts/LoginPage.xaml.cs @@ -0,0 +1,27 @@ +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 + { + private LoginPageViewModel _vm; + + public LoginPage() + { + InitializeComponent(); + _vm = BindingContext as LoginPageViewModel; + _vm.Page = this; + } + + private async void LogIn_Clicked(object sender, EventArgs e) + { + await _vm.LogInAsync(); + } + } +} diff --git a/src/App/Pages/Accounts/LoginPageViewModel.cs b/src/App/Pages/Accounts/LoginPageViewModel.cs new file mode 100644 index 000000000..056903911 --- /dev/null +++ b/src/App/Pages/Accounts/LoginPageViewModel.cs @@ -0,0 +1,75 @@ +using Bit.App.Abstractions; +using Bit.App.Resources; +using Bit.Core.Abstractions; +using Bit.Core.Exceptions; +using Bit.Core.Utilities; +using System.Threading.Tasks; +using System.Windows.Input; +using Xamarin.Forms; + +namespace Bit.App.Pages +{ + public class LoginPageViewModel : BaseViewModel + { + private readonly IDeviceActionService _deviceActionService; + private readonly IAuthService _authService; + + public LoginPageViewModel() + { + _deviceActionService = ServiceContainer.Resolve("deviceActionService"); + _authService = ServiceContainer.Resolve("authService"); + + PageTitle = AppResources.Bitwarden; + ShowPasswordCommand = new Command(() => + Page.DisplayAlert("Button 1 Command", "Button 1 message", "Cancel")); + } + + public ICommand ShowPasswordCommand { get; } + public string Email { get; set; } + public string MasterPassword { get; set; } + + public async Task LogInAsync() + { + if(string.IsNullOrWhiteSpace(Email)) + { + await Page.DisplayAlert(AppResources.AnErrorHasOccurred, + string.Format(AppResources.ValidationFieldRequired, AppResources.EmailAddress), + AppResources.Ok); + return; + } + if(!Email.Contains("@")) + { + await Page.DisplayAlert(AppResources.AnErrorHasOccurred, AppResources.InvalidEmail, AppResources.Ok); + return; + } + if(string.IsNullOrWhiteSpace(MasterPassword)) + { + await Page.DisplayAlert(AppResources.AnErrorHasOccurred, + string.Format(AppResources.ValidationFieldRequired, AppResources.MasterPassword), + AppResources.Ok); + return; + } + + try + { + await _deviceActionService.ShowLoadingAsync(AppResources.LoggingIn); + var response = await _authService.LogInAsync(Email, MasterPassword); + await _deviceActionService.HideLoadingAsync(); + // TODO: remember email? + if(response.TwoFactor) + { + // TODO: 2fa page + } + else + { + Application.Current.MainPage = new TabsPage(); + } + } + catch(ApiException e) + { + await _deviceActionService.HideLoadingAsync(); + await Page.DisplayAlert(AppResources.AnErrorHasOccurred, e.Error.GetSingleMessage(), AppResources.Ok); + } + } + } +} diff --git a/src/App/Pages/HomePage.xaml b/src/App/Pages/HomePage.xaml index 87f18f48e..3d5c6c2e3 100644 --- a/src/App/Pages/HomePage.xaml +++ b/src/App/Pages/HomePage.xaml @@ -23,7 +23,7 @@ class="text-lg" HorizontalTextAlignment="Center"> + Clicked="LogIn_Clicked"> diff --git a/src/App/Pages/HomePage.xaml.cs b/src/App/Pages/HomePage.xaml.cs index d4868c2a6..342dcfd6e 100644 --- a/src/App/Pages/HomePage.xaml.cs +++ b/src/App/Pages/HomePage.xaml.cs @@ -14,5 +14,10 @@ namespace Bit.App.Pages { InitializeComponent(); } + + private void LogIn_Clicked(object sender, EventArgs e) + { + Navigation.PushModalAsync(new NavigationPage(new LoginPage())); + } } } diff --git a/src/App/Resources/AppResources.Designer.cs b/src/App/Resources/AppResources.Designer.cs index 22c1f8e55..60be79d0c 100644 --- a/src/App/Resources/AppResources.Designer.cs +++ b/src/App/Resources/AppResources.Designer.cs @@ -19,7 +19,7 @@ namespace Bit.App.Resources { // class via a tool like ResGen or Visual Studio. // To add or remove a member, edit your .ResX file then rerun ResGen // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")] [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] internal class AppResources { @@ -1788,6 +1788,15 @@ namespace Bit.App.Resources { } } + /// + /// Looks up a localized string similar to Invalid email address.. + /// + internal static string InvalidEmail { + get { + return ResourceManager.GetString("InvalidEmail", resourceCulture); + } + } + /// /// Looks up a localized string similar to Invalid Master Password. Try again.. /// diff --git a/src/App/Resources/AppResources.resx b/src/App/Resources/AppResources.resx index 2e8ef35d5..254471511 100644 --- a/src/App/Resources/AppResources.resx +++ b/src/App/Resources/AppResources.resx @@ -1346,4 +1346,7 @@ The easiest way to add new logins to your vault is by using the Bitwarden Password AutoFill extension. Learn more about using the Bitwarden Password AutoFill extension by navigating to the "Tools" screen. + + Invalid email address. + \ No newline at end of file