mirror of
https://github.com/bitwarden/android.git
synced 2024-12-18 23:31:52 +03:00
autofill WIP into main activity. created login selection page
This commit is contained in:
parent
61e0379eb3
commit
26667c0a59
10 changed files with 266 additions and 51 deletions
|
@ -298,7 +298,6 @@
|
|||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="AutofillSelectLoginActivity.cs" />
|
||||
<Compile Include="AutofillActivity.cs" />
|
||||
<Compile Include="Controls\CustomSearchBarRenderer.cs" />
|
||||
<Compile Include="Controls\CustomButtonRenderer.cs" />
|
||||
|
|
|
@ -7,17 +7,17 @@ using Android.App;
|
|||
using Android.Content;
|
||||
using Android.OS;
|
||||
using Android.Runtime;
|
||||
using Bit.App.Models;
|
||||
using Android.Views;
|
||||
|
||||
namespace Bit.Android
|
||||
{
|
||||
[Activity(Label = "bitwarden Autofill",
|
||||
[Activity(Label = "bitwarden",
|
||||
Icon = "@drawable/icon",
|
||||
LaunchMode = global::Android.Content.PM.LaunchMode.SingleInstance,
|
||||
Theme = "@style/android:Theme.Material.Light")]
|
||||
WindowSoftInputMode = SoftInput.StateHidden)]
|
||||
public class AutofillActivity : Activity
|
||||
{
|
||||
private string _lastQueriedUri;
|
||||
|
||||
public static Credentials LastCredentials;
|
||||
|
||||
protected override void OnCreate(Bundle bundle)
|
||||
|
@ -25,12 +25,11 @@ namespace Bit.Android
|
|||
base.OnCreate(bundle);
|
||||
_lastQueriedUri = Intent.GetStringExtra("uri");
|
||||
|
||||
var intent = new Intent(this, typeof(AutofillSelectLoginActivity));
|
||||
var intent = new Intent(this, typeof(MainActivity));
|
||||
intent.PutExtra("uri", _lastQueriedUri);
|
||||
StartActivityForResult(intent, 123);
|
||||
}
|
||||
|
||||
|
||||
protected override void OnActivityResult(int requestCode, [GeneratedEnum] Result resultCode, Intent data)
|
||||
{
|
||||
base.OnActivityResult(requestCode, resultCode, data);
|
||||
|
@ -62,4 +61,4 @@ namespace Bit.Android
|
|||
public string Uri;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Android.App;
|
||||
using Android.Content;
|
||||
using Android.OS;
|
||||
|
||||
namespace Bit.Android
|
||||
{
|
||||
[Activity(LaunchMode = global::Android.Content.PM.LaunchMode.SingleInstance)]
|
||||
public class AutofillSelectLoginActivity : Activity
|
||||
{
|
||||
protected override void OnCreate(Bundle bundle)
|
||||
{
|
||||
base.OnCreate(bundle);
|
||||
var uri = Intent.GetStringExtra("uri");
|
||||
|
||||
Intent data = new Intent();
|
||||
data.PutExtra("uri", uri);
|
||||
data.PutExtra("username", "user123");
|
||||
data.PutExtra("password", "pass123");
|
||||
|
||||
if(Parent == null)
|
||||
{
|
||||
SetResult(Result.Ok, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
Parent.SetResult(Result.Ok, data);
|
||||
}
|
||||
|
||||
Finish();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@ using System.Reflection;
|
|||
using Xamarin.Forms.Platform.Android;
|
||||
using Xamarin.Forms;
|
||||
using System.Threading.Tasks;
|
||||
using Bit.App.Models.Page;
|
||||
|
||||
namespace Bit.Android
|
||||
{
|
||||
|
@ -27,6 +28,12 @@ namespace Bit.Android
|
|||
|
||||
protected override void OnCreate(Bundle bundle)
|
||||
{
|
||||
var uri = Intent.GetStringExtra("uri");
|
||||
if(uri != null && !Resolver.IsSet)
|
||||
{
|
||||
MainApplication.SetIoc(Application);
|
||||
}
|
||||
|
||||
var policy = new StrictMode.ThreadPolicy.Builder().PermitAll().Build();
|
||||
StrictMode.SetThreadPolicy(policy);
|
||||
|
||||
|
@ -55,6 +62,7 @@ namespace Bit.Android
|
|||
.SetValue(null, Color.FromHex("d2d6de"));
|
||||
|
||||
LoadApplication(new App.App(
|
||||
uri,
|
||||
Resolver.Resolve<IAuthService>(),
|
||||
Resolver.Resolve<IConnectivity>(),
|
||||
Resolver.Resolve<IUserDialogs>(),
|
||||
|
@ -70,6 +78,31 @@ namespace Bit.Android
|
|||
{
|
||||
RateApp();
|
||||
});
|
||||
|
||||
MessagingCenter.Subscribe<Xamarin.Forms.Application, VaultListPageModel.Login>(
|
||||
Xamarin.Forms.Application.Current, "Autofill", (sender, args) =>
|
||||
{
|
||||
ReturnCredentials(args);
|
||||
});
|
||||
}
|
||||
|
||||
private void ReturnCredentials(VaultListPageModel.Login login)
|
||||
{
|
||||
Intent data = new Intent();
|
||||
data.PutExtra("uri", login.Uri.Value);
|
||||
data.PutExtra("username", login.Username);
|
||||
data.PutExtra("password", login.Password.Value);
|
||||
|
||||
if(Parent == null)
|
||||
{
|
||||
SetResult(Result.Ok, data);
|
||||
}
|
||||
else
|
||||
{
|
||||
Parent.SetResult(Result.Ok, data);
|
||||
}
|
||||
|
||||
Finish();
|
||||
}
|
||||
|
||||
protected override void OnPause()
|
||||
|
|
|
@ -43,7 +43,7 @@ namespace Bit.Android
|
|||
|
||||
if(!Resolver.IsSet)
|
||||
{
|
||||
SetIoc();
|
||||
SetIoc(this);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -178,16 +178,16 @@ namespace Bit.Android
|
|||
}
|
||||
}
|
||||
|
||||
private void SetIoc()
|
||||
public static void SetIoc(Application application)
|
||||
{
|
||||
UserDialogs.Init(this);
|
||||
UserDialogs.Init(application);
|
||||
|
||||
var container = new UnityContainer();
|
||||
|
||||
container
|
||||
// Android Stuff
|
||||
.RegisterInstance(ApplicationContext)
|
||||
.RegisterInstance<Application>(this)
|
||||
.RegisterInstance(application.ApplicationContext)
|
||||
.RegisterInstance<Application>(application)
|
||||
// Services
|
||||
.RegisterType<IDatabaseService, DatabaseService>(new ContainerControlledLifetimeManager())
|
||||
.RegisterType<ISqlService, SqlService>(new ContainerControlledLifetimeManager())
|
||||
|
|
|
@ -19,6 +19,7 @@ namespace Bit.App
|
|||
{
|
||||
public class App : Application
|
||||
{
|
||||
private readonly string _uri;
|
||||
private readonly IDatabaseService _databaseService;
|
||||
private readonly IConnectivity _connectivity;
|
||||
private readonly IUserDialogs _userDialogs;
|
||||
|
@ -31,6 +32,7 @@ namespace Bit.App
|
|||
private readonly ILocalizeService _localizeService;
|
||||
|
||||
public App(
|
||||
string uri,
|
||||
IAuthService authService,
|
||||
IConnectivity connectivity,
|
||||
IUserDialogs userDialogs,
|
||||
|
@ -42,6 +44,7 @@ namespace Bit.App
|
|||
IGoogleAnalyticsService googleAnalyticsService,
|
||||
ILocalizeService localizeService)
|
||||
{
|
||||
_uri = uri;
|
||||
_databaseService = databaseService;
|
||||
_connectivity = connectivity;
|
||||
_userDialogs = userDialogs;
|
||||
|
@ -56,7 +59,11 @@ namespace Bit.App
|
|||
SetCulture();
|
||||
SetStyles();
|
||||
|
||||
if(authService.IsAuthenticated)
|
||||
if(authService.IsAuthenticated && _uri != null)
|
||||
{
|
||||
MainPage = new ExtendedNavigationPage(new VaultAutofillListLoginsPage(_uri));
|
||||
}
|
||||
else if(authService.IsAuthenticated)
|
||||
{
|
||||
MainPage = new MainPage();
|
||||
}
|
||||
|
|
|
@ -134,6 +134,7 @@
|
|||
<Compile Include="Pages\Settings\SettingsSyncPage.cs" />
|
||||
<Compile Include="Pages\Settings\SettingsPage.cs" />
|
||||
<Compile Include="Pages\Settings\SettingsListFoldersPage.cs" />
|
||||
<Compile Include="Pages\Vault\VaultAutofillListLoginsPage.cs" />
|
||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||
<Compile Include="Abstractions\Repositories\ILoginRepository.cs" />
|
||||
<Compile Include="Repositories\ApiRepository.cs" />
|
||||
|
|
|
@ -8,6 +8,8 @@ namespace Bit.App.Models.Page
|
|||
{
|
||||
public class Login
|
||||
{
|
||||
private string _baseDomain;
|
||||
|
||||
public Login(Models.Login login)
|
||||
{
|
||||
Id = login.Id;
|
||||
|
@ -24,6 +26,37 @@ namespace Bit.App.Models.Page
|
|||
public string Username { get; set; }
|
||||
public Lazy<string> Password { get; set; }
|
||||
public Lazy<string> Uri { get; set; }
|
||||
|
||||
public string BaseDomain
|
||||
{
|
||||
get
|
||||
{
|
||||
if(_baseDomain != null)
|
||||
{
|
||||
return _baseDomain;
|
||||
}
|
||||
|
||||
if(string.IsNullOrWhiteSpace(Uri.Value))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
Uri uri;
|
||||
if(!System.Uri.TryCreate(Uri.Value, UriKind.Absolute, out uri))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
DomainName domain;
|
||||
if(!DomainName.TryParse(uri.Host, out domain))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
_baseDomain = domain.BaseDomain;
|
||||
return _baseDomain;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class Folder : List<Login>
|
||||
|
|
179
src/App/Pages/Vault/VaultAutofillListLoginsPage.cs
Normal file
179
src/App/Pages/Vault/VaultAutofillListLoginsPage.cs
Normal file
|
@ -0,0 +1,179 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Acr.UserDialogs;
|
||||
using Bit.App.Abstractions;
|
||||
using Bit.App.Controls;
|
||||
using Bit.App.Models.Page;
|
||||
using Bit.App.Resources;
|
||||
using Xamarin.Forms;
|
||||
using XLabs.Ioc;
|
||||
using Bit.App.Utilities;
|
||||
using PushNotification.Plugin.Abstractions;
|
||||
using Plugin.Settings.Abstractions;
|
||||
using Plugin.Connectivity.Abstractions;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Bit.App.Models;
|
||||
|
||||
namespace Bit.App.Pages
|
||||
{
|
||||
public class VaultAutofillListLoginsPage : ExtendedContentPage
|
||||
{
|
||||
private readonly IFolderService _folderService;
|
||||
private readonly ILoginService _loginService;
|
||||
private readonly IUserDialogs _userDialogs;
|
||||
private readonly IConnectivity _connectivity;
|
||||
private readonly IClipboardService _clipboardService;
|
||||
private readonly ISyncService _syncService;
|
||||
private readonly IPushNotification _pushNotification;
|
||||
private readonly IDeviceInfoService _deviceInfoService;
|
||||
private readonly ISettings _settings;
|
||||
private CancellationTokenSource _filterResultsCancellationTokenSource;
|
||||
private readonly DomainName _domainName;
|
||||
|
||||
public VaultAutofillListLoginsPage(string uriString)
|
||||
: base(true)
|
||||
{
|
||||
Uri uri;
|
||||
if(Uri.TryCreate(uriString, UriKind.RelativeOrAbsolute, out uri) &&
|
||||
DomainName.TryParse(uri.Host, out _domainName)) { }
|
||||
|
||||
_folderService = Resolver.Resolve<IFolderService>();
|
||||
_loginService = Resolver.Resolve<ILoginService>();
|
||||
_connectivity = Resolver.Resolve<IConnectivity>();
|
||||
_userDialogs = Resolver.Resolve<IUserDialogs>();
|
||||
_clipboardService = Resolver.Resolve<IClipboardService>();
|
||||
_syncService = Resolver.Resolve<ISyncService>();
|
||||
_pushNotification = Resolver.Resolve<IPushNotification>();
|
||||
_deviceInfoService = Resolver.Resolve<IDeviceInfoService>();
|
||||
_settings = Resolver.Resolve<ISettings>();
|
||||
|
||||
Init();
|
||||
}
|
||||
public ExtendedObservableCollection<VaultListPageModel.Login> PresentationLogins { get; private set; }
|
||||
= new ExtendedObservableCollection<VaultListPageModel.Login>();
|
||||
|
||||
public ListView ListView { get; set; }
|
||||
|
||||
private void Init()
|
||||
{
|
||||
MessagingCenter.Subscribe<Application, bool>(Application.Current, "SyncCompleted", (sender, success) =>
|
||||
{
|
||||
if(success)
|
||||
{
|
||||
_filterResultsCancellationTokenSource = FetchAndLoadVault();
|
||||
}
|
||||
});
|
||||
|
||||
ToolbarItems.Add(new AddLoginToolBarItem(this));
|
||||
|
||||
ListView = new ListView(ListViewCachingStrategy.RecycleElement)
|
||||
{
|
||||
ItemsSource = PresentationLogins,
|
||||
HasUnevenRows = true,
|
||||
ItemTemplate = new DataTemplate(() => new VaultListViewCell(this))
|
||||
};
|
||||
|
||||
if(Device.OS == TargetPlatform.iOS)
|
||||
{
|
||||
ListView.RowHeight = -1;
|
||||
}
|
||||
|
||||
ListView.ItemSelected += LoginSelected;
|
||||
|
||||
Title = AppResources.Logins;
|
||||
|
||||
Content = ListView;
|
||||
}
|
||||
|
||||
protected override void OnAppearing()
|
||||
{
|
||||
base.OnAppearing();
|
||||
_filterResultsCancellationTokenSource = FetchAndLoadVault();
|
||||
}
|
||||
|
||||
private CancellationTokenSource FetchAndLoadVault()
|
||||
{
|
||||
var cts = new CancellationTokenSource();
|
||||
_settings.AddOrUpdateValue(Constants.FirstVaultLoad, false);
|
||||
|
||||
if(PresentationLogins.Count > 0 && _syncService.SyncInProgress)
|
||||
{
|
||||
return cts;
|
||||
}
|
||||
|
||||
_filterResultsCancellationTokenSource?.Cancel();
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
var logins = await _loginService.GetAllAsync();
|
||||
var filteredLogins = logins
|
||||
.Select(s => new VaultListPageModel.Login(s))
|
||||
.Where(s => s.BaseDomain != null && s.BaseDomain == _domainName.BaseDomain)
|
||||
.OrderBy(s => s.Name)
|
||||
.ThenBy(s => s.Username)
|
||||
.ToArray();
|
||||
|
||||
PresentationLogins.ResetWithRange(filteredLogins);
|
||||
}, cts.Token);
|
||||
|
||||
return cts;
|
||||
}
|
||||
|
||||
private void LoginSelected(object sender, SelectedItemChangedEventArgs e)
|
||||
{
|
||||
var login = e.SelectedItem as VaultListPageModel.Login;
|
||||
MessagingCenter.Send(Application.Current, "Autofill", login);
|
||||
}
|
||||
|
||||
private async void AddLogin()
|
||||
{
|
||||
var page = new VaultAddLoginPage();
|
||||
await Navigation.PushForDeviceAsync(page);
|
||||
}
|
||||
|
||||
private class AddLoginToolBarItem : ToolbarItem
|
||||
{
|
||||
private readonly VaultAutofillListLoginsPage _page;
|
||||
|
||||
public AddLoginToolBarItem(VaultAutofillListLoginsPage page)
|
||||
{
|
||||
_page = page;
|
||||
Text = AppResources.Add;
|
||||
Icon = "plus";
|
||||
Clicked += ClickedItem;
|
||||
}
|
||||
|
||||
private void ClickedItem(object sender, EventArgs e)
|
||||
{
|
||||
_page.AddLogin();
|
||||
}
|
||||
}
|
||||
|
||||
private class VaultListViewCell : LabeledDetailCell
|
||||
{
|
||||
private VaultAutofillListLoginsPage _page;
|
||||
|
||||
public static readonly BindableProperty LoginParameterProperty = BindableProperty.Create(nameof(LoginParameter),
|
||||
typeof(VaultListPageModel.Login), typeof(VaultListViewCell), null);
|
||||
|
||||
public VaultListViewCell(VaultAutofillListLoginsPage page)
|
||||
{
|
||||
_page = page;
|
||||
|
||||
SetBinding(LoginParameterProperty, new Binding("."));
|
||||
Label.SetBinding<VaultListPageModel.Login>(Label.TextProperty, s => s.Name);
|
||||
Detail.SetBinding<VaultListPageModel.Login>(Label.TextProperty, s => s.Username);
|
||||
|
||||
BackgroundColor = Color.White;
|
||||
}
|
||||
|
||||
public VaultListPageModel.Login LoginParameter
|
||||
{
|
||||
get { return GetValue(LoginParameterProperty) as VaultListPageModel.Login; }
|
||||
set { SetValue(LoginParameterProperty, value); }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -56,6 +56,7 @@ namespace Bit.iOS
|
|||
manager.DisableMetricsManager = manager.DisableFeedbackManager = manager.DisableUpdateManager = true;
|
||||
|
||||
LoadApplication(new App.App(
|
||||
null,
|
||||
Resolver.Resolve<IAuthService>(),
|
||||
Resolver.Resolve<IConnectivity>(),
|
||||
Resolver.Resolve<IUserDialogs>(),
|
||||
|
|
Loading…
Reference in a new issue