bitwarden-android/src/App/Pages/Vault/VaultAutofillListLoginsPage.cs

242 lines
8.2 KiB
C#
Raw Normal View History

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 System.Threading;
using Bit.App.Models;
2017-01-31 03:26:39 +03:00
using System.Collections.Generic;
namespace Bit.App.Pages
{
public class VaultAutofillListLoginsPage : ExtendedContentPage
{
private readonly ILoginService _loginService;
private readonly IUserDialogs _userDialogs;
private readonly IClipboardService _clipboardService;
private CancellationTokenSource _filterResultsCancellationTokenSource;
private readonly DomainName _domainName;
2017-01-31 03:26:39 +03:00
private readonly string _uri;
private readonly string _name;
private readonly bool _androidApp = false;
public VaultAutofillListLoginsPage(string uriString)
: base(true)
{
2017-01-31 03:26:39 +03:00
_uri = uriString;
Uri uri;
2017-01-31 03:26:39 +03:00
if(!Uri.TryCreate(uriString, UriKind.RelativeOrAbsolute, out uri) ||
!DomainName.TryParse(uri.Host, out _domainName))
{
if(uriString != null && uriString.StartsWith(Constants.AndroidAppProtocol))
{
_androidApp = true;
_name = uriString.Substring(Constants.AndroidAppProtocol.Length);
}
}
else
{
_name = _domainName.BaseDomain;
}
_loginService = Resolver.Resolve<ILoginService>();
_userDialogs = Resolver.Resolve<IUserDialogs>();
_clipboardService = Resolver.Resolve<IClipboardService>();
Init();
}
public ExtendedObservableCollection<VaultListPageModel.Login> PresentationLogins { get; private set; }
= new ExtendedObservableCollection<VaultListPageModel.Login>();
2017-01-31 03:26:39 +03:00
public StackLayout NoDataStackLayout { get; set; }
public ListView ListView { get; set; }
2017-01-31 03:26:39 +03:00
public ActivityIndicator LoadingIndicator { get; set; }
private void Init()
{
MessagingCenter.Subscribe<Application, bool>(Application.Current, "SyncCompleted", (sender, success) =>
{
if(success)
{
_filterResultsCancellationTokenSource = FetchAndLoadVault();
}
});
2017-01-31 03:26:39 +03:00
var noDataLabel = new Label
{
Text = string.Format(AppResources.NoLoginsForUri, _name ?? "--"),
HorizontalTextAlignment = TextAlignment.Center,
FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)),
Style = (Style)Application.Current.Resources["text-muted"]
};
var addLoginButton = new ExtendedButton
{
Text = AppResources.AddALogin,
Command = new Command(() => AddLoginAsync()),
Style = (Style)Application.Current.Resources["btn-primaryAccent"]
};
NoDataStackLayout = new StackLayout
{
Children = { noDataLabel, addLoginButton },
VerticalOptions = LayoutOptions.CenterAndExpand,
Padding = new Thickness(20, 0),
Spacing = 20
};
ToolbarItems.Add(new AddLoginToolBarItem(this));
ListView = new ListView(ListViewCachingStrategy.RecycleElement)
{
ItemsSource = PresentationLogins,
HasUnevenRows = true,
2017-01-31 03:26:39 +03:00
ItemTemplate = new DataTemplate(() => new VaultListViewCell(
(VaultListPageModel.Login l) => MoreClickedAsync(l)))
};
if(Device.OS == TargetPlatform.iOS)
{
ListView.RowHeight = -1;
}
ListView.ItemSelected += LoginSelected;
2017-01-31 03:26:39 +03:00
Title = string.Format(AppResources.LoginsForUri, _name ?? "--");
LoadingIndicator = new ActivityIndicator
{
IsRunning = true,
VerticalOptions = LayoutOptions.CenterAndExpand,
HorizontalOptions = LayoutOptions.Center
};
2017-01-31 03:26:39 +03:00
Content = LoadingIndicator;
}
protected override void OnAppearing()
{
base.OnAppearing();
_filterResultsCancellationTokenSource = FetchAndLoadVault();
}
2017-01-31 03:26:39 +03:00
protected override bool OnBackButtonPressed()
{
2017-01-31 03:26:39 +03:00
MessagingCenter.Send(Application.Current, "Autofill", (VaultListPageModel.Login)null);
return true;
}
2017-01-31 03:26:39 +03:00
private void AdjustContent()
{
if(PresentationLogins.Count > 0)
{
Content = ListView;
}
else
{
2017-01-31 03:26:39 +03:00
Content = NoDataStackLayout;
}
2017-01-31 03:26:39 +03:00
}
2017-01-31 03:26:39 +03:00
private CancellationTokenSource FetchAndLoadVault()
{
var cts = new CancellationTokenSource();
_filterResultsCancellationTokenSource?.Cancel();
Task.Run(async () =>
{
var logins = await _loginService.GetAllAsync();
var filteredLogins = logins
.Select(s => new VaultListPageModel.Login(s))
2017-01-31 03:26:39 +03:00
.Where(s => (_androidApp && _domainName == null && s.Uri.Value == _uri) ||
(_domainName != null && s.BaseDomain != null && s.BaseDomain == _domainName.BaseDomain))
.OrderBy(s => s.Name)
2017-01-31 03:26:39 +03:00
.ThenBy(s => s.Username);
2017-01-31 03:26:39 +03:00
Device.BeginInvokeOnMainThread(() =>
{
PresentationLogins.ResetWithRange(filteredLogins);
AdjustContent();
});
}, cts.Token);
return cts;
}
private void LoginSelected(object sender, SelectedItemChangedEventArgs e)
{
var login = e.SelectedItem as VaultListPageModel.Login;
MessagingCenter.Send(Application.Current, "Autofill", login);
}
2017-01-31 03:26:39 +03:00
private async void AddLoginAsync()
{
2017-01-31 03:26:39 +03:00
var page = new VaultAddLoginPage(_uri, _name);
await Navigation.PushForDeviceAsync(page);
}
2017-01-31 03:26:39 +03:00
private async void MoreClickedAsync(VaultListPageModel.Login login)
{
2017-01-31 03:26:39 +03:00
var buttons = new List<string> { AppResources.View, AppResources.Edit };
if(!string.IsNullOrWhiteSpace(login.Password.Value))
{
2017-01-31 03:26:39 +03:00
buttons.Add(AppResources.CopyPassword);
}
if(!string.IsNullOrWhiteSpace(login.Username))
{
buttons.Add(AppResources.CopyUsername);
}
2017-01-31 03:26:39 +03:00
var selection = await DisplayActionSheet(login.Name, AppResources.Cancel, null, buttons.ToArray());
if(selection == AppResources.View)
{
var page = new VaultViewLoginPage(login.Id);
await Navigation.PushForDeviceAsync(page);
}
else if(selection == AppResources.Edit)
{
2017-01-31 03:26:39 +03:00
var page = new VaultEditLoginPage(login.Id);
await Navigation.PushForDeviceAsync(page);
}
else if(selection == AppResources.CopyPassword)
{
Copy(login.Password.Value, AppResources.Password);
}
else if(selection == AppResources.CopyUsername)
{
Copy(login.Username, AppResources.Username);
}
}
2017-01-31 03:26:39 +03:00
private void Copy(string copyText, string alertLabel)
{
2017-01-31 03:26:39 +03:00
_clipboardService.CopyToClipboard(copyText);
_userDialogs.Toast(string.Format(AppResources.ValueHasBeenCopied, alertLabel));
}
2017-01-31 03:26:39 +03:00
private class AddLoginToolBarItem : ToolbarItem
{
private readonly VaultAutofillListLoginsPage _page;
2017-01-31 03:26:39 +03:00
public AddLoginToolBarItem(VaultAutofillListLoginsPage page)
{
_page = page;
2017-01-31 03:26:39 +03:00
Text = AppResources.Add;
Icon = "plus";
Clicked += ClickedItem;
}
2017-01-31 03:26:39 +03:00
private void ClickedItem(object sender, EventArgs e)
{
2017-01-31 03:26:39 +03:00
_page.AddLoginAsync();
}
}
}
}