mirror of
https://github.com/bitwarden/android.git
synced 2024-12-21 08:42:39 +03:00
added search to vault list page.
This commit is contained in:
parent
f2ed6a4d33
commit
f9fd53c733
2 changed files with 93 additions and 26 deletions
|
@ -10,10 +10,10 @@ namespace Bit.App.Models.Page
|
||||||
{
|
{
|
||||||
public class Site
|
public class Site
|
||||||
{
|
{
|
||||||
public Site(Models.Site site, string folderId)
|
public Site(Models.Site site)
|
||||||
{
|
{
|
||||||
Id = site.Id;
|
Id = site.Id;
|
||||||
FolderId = folderId;
|
FolderId = site.FolderId;
|
||||||
Name = site.Name?.Decrypt();
|
Name = site.Name?.Decrypt();
|
||||||
Username = site.Username?.Decrypt() ?? " ";
|
Username = site.Username?.Decrypt() ?? " ";
|
||||||
Password = new Lazy<string>(() => site.Password?.Decrypt());
|
Password = new Lazy<string>(() => site.Password?.Decrypt());
|
||||||
|
@ -30,19 +30,17 @@ namespace Bit.App.Models.Page
|
||||||
|
|
||||||
public class Folder : List<Site>
|
public class Folder : List<Site>
|
||||||
{
|
{
|
||||||
public Folder(IEnumerable<Models.Site> sites, string folderId = null)
|
public Folder(Models.Folder folder)
|
||||||
{
|
|
||||||
var pageSites = sites.Select(s => new Site(s, folderId)).OrderBy(s => s.Name);
|
|
||||||
AddRange(pageSites);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Folder(Models.Folder folder, IEnumerable<Models.Site> sites)
|
|
||||||
: this(sites, folder.Id)
|
|
||||||
{
|
{
|
||||||
Id = folder.Id;
|
Id = folder.Id;
|
||||||
Name = folder.Name?.Decrypt();
|
Name = folder.Name?.Decrypt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Folder(IEnumerable<Site> sites)
|
||||||
|
{
|
||||||
|
AddRange(sites);
|
||||||
|
}
|
||||||
|
|
||||||
public string Id { get; set; }
|
public string Id { get; set; }
|
||||||
public string Name { get; set; } = AppResources.FolderNone;
|
public string Name { get; set; } = AppResources.FolderNone;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ using PushNotification.Plugin.Abstractions;
|
||||||
using Plugin.Settings.Abstractions;
|
using Plugin.Settings.Abstractions;
|
||||||
using Plugin.Connectivity.Abstractions;
|
using Plugin.Connectivity.Abstractions;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Bit.App.Models;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
|
@ -42,13 +43,17 @@ namespace Bit.App.Pages
|
||||||
Init();
|
Init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ExtendedObservableCollection<VaultListPageModel.Folder> Folders { get; private set; } = new ExtendedObservableCollection<VaultListPageModel.Folder>();
|
public ExtendedObservableCollection<VaultListPageModel.Folder> PresentationFolders { get; private set; }
|
||||||
|
= new ExtendedObservableCollection<VaultListPageModel.Folder>();
|
||||||
|
public ListView ListView { get; set; }
|
||||||
|
public IEnumerable<VaultListPageModel.Site> Sites { get; set; } = new List<VaultListPageModel.Site>();
|
||||||
|
public IEnumerable<VaultListPageModel.Folder> Folders { get; set; } = new List<VaultListPageModel.Folder>();
|
||||||
|
|
||||||
private void Init()
|
private void Init()
|
||||||
{
|
{
|
||||||
MessagingCenter.Subscribe<Application>(Application.Current, "SyncCompleted", async (sender) =>
|
MessagingCenter.Subscribe<Application>(Application.Current, "SyncCompleted", async (sender) =>
|
||||||
{
|
{
|
||||||
await LoadFoldersAsync();
|
await FetchAndLoadVaultAsync();
|
||||||
});
|
});
|
||||||
|
|
||||||
if(!_favorites)
|
if(!_favorites)
|
||||||
|
@ -56,10 +61,10 @@ namespace Bit.App.Pages
|
||||||
ToolbarItems.Add(new AddSiteToolBarItem(this));
|
ToolbarItems.Add(new AddSiteToolBarItem(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
var listView = new ListView
|
ListView = new ListView
|
||||||
{
|
{
|
||||||
IsGroupingEnabled = true,
|
IsGroupingEnabled = true,
|
||||||
ItemsSource = Folders,
|
ItemsSource = PresentationFolders,
|
||||||
HasUnevenRows = true,
|
HasUnevenRows = true,
|
||||||
GroupHeaderTemplate = new DataTemplate(() => new VaultListHeaderViewCell(this)),
|
GroupHeaderTemplate = new DataTemplate(() => new VaultListHeaderViewCell(this)),
|
||||||
ItemTemplate = new DataTemplate(() => new VaultListViewCell(this))
|
ItemTemplate = new DataTemplate(() => new VaultListViewCell(this))
|
||||||
|
@ -67,19 +72,62 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
if(Device.OS == TargetPlatform.iOS)
|
if(Device.OS == TargetPlatform.iOS)
|
||||||
{
|
{
|
||||||
listView.RowHeight = -1;
|
ListView.RowHeight = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
listView.ItemSelected += SiteSelected;
|
ListView.ItemSelected += SiteSelected;
|
||||||
|
|
||||||
|
var searchBar = new SearchBar
|
||||||
|
{
|
||||||
|
Placeholder = "Search vault...",
|
||||||
|
BackgroundColor = Color.FromHex("efeff4")
|
||||||
|
};
|
||||||
|
searchBar.TextChanged += SearchBar_TextChanged;
|
||||||
|
searchBar.SearchButtonPressed += SearchBar_SearchButtonPressed;
|
||||||
|
|
||||||
Title = _favorites ? AppResources.Favorites : AppResources.MyVault;
|
Title = _favorites ? AppResources.Favorites : AppResources.MyVault;
|
||||||
Content = listView;
|
Content = new StackLayout
|
||||||
|
{
|
||||||
|
Children = { searchBar, ListView },
|
||||||
|
Spacing = 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SearchBar_SearchButtonPressed(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
FilterResults(((SearchBar)sender).Text);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SearchBar_TextChanged(object sender, TextChangedEventArgs e)
|
||||||
|
{
|
||||||
|
var oldLength = e.OldTextValue?.Length ?? 0;
|
||||||
|
var newLength = e.NewTextValue?.Length ?? 0;
|
||||||
|
if(oldLength < 2 && newLength < 2 && oldLength < newLength)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FilterResults(e.NewTextValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void FilterResults(string searchFilter)
|
||||||
|
{
|
||||||
|
if(string.IsNullOrWhiteSpace(searchFilter))
|
||||||
|
{
|
||||||
|
LoadFolders(Sites);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
searchFilter = searchFilter.ToLower();
|
||||||
|
var filteredSites = Sites.Where(s => s.Name.ToLower().Contains(searchFilter) || s.Username.ToLower().Contains(searchFilter));
|
||||||
|
LoadFolders(filteredSites);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected async override void OnAppearing()
|
protected async override void OnAppearing()
|
||||||
{
|
{
|
||||||
base.OnAppearing();
|
base.OnAppearing();
|
||||||
LoadFoldersAsync().Wait();
|
await FetchAndLoadVaultAsync();
|
||||||
|
|
||||||
if(_connectivity.IsConnected && Device.OS == TargetPlatform.iOS && !_favorites)
|
if(_connectivity.IsConnected && Device.OS == TargetPlatform.iOS && !_favorites)
|
||||||
{
|
{
|
||||||
|
@ -101,17 +149,38 @@ namespace Bit.App.Pages
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task LoadFoldersAsync()
|
private async Task FetchAndLoadVaultAsync()
|
||||||
{
|
{
|
||||||
var folders = await _folderService.GetAllAsync();
|
var foldersTask = _folderService.GetAllAsync();
|
||||||
var sites = _favorites ? await _siteService.GetAllAsync(true) : await _siteService.GetAllAsync();
|
var sitesTask = _favorites ? _siteService.GetAllAsync(true) : _siteService.GetAllAsync();
|
||||||
|
await Task.WhenAll(foldersTask, sitesTask);
|
||||||
|
|
||||||
|
var folders = await foldersTask;
|
||||||
|
var sites = await sitesTask;
|
||||||
|
|
||||||
|
Folders = folders.Select(f => new VaultListPageModel.Folder(f));
|
||||||
|
Sites = sites.Select(s => new VaultListPageModel.Site(s));
|
||||||
|
|
||||||
|
LoadFolders(Sites);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LoadFolders(IEnumerable<VaultListPageModel.Site> sites)
|
||||||
|
{
|
||||||
|
var folders = new List<VaultListPageModel.Folder>(Folders);
|
||||||
|
|
||||||
|
foreach(var folder in folders)
|
||||||
|
{
|
||||||
|
if(folder.Any())
|
||||||
|
{
|
||||||
|
folder.Clear();
|
||||||
|
}
|
||||||
|
folder.AddRange(sites.Where(s => s.FolderId == folder.Id));
|
||||||
|
}
|
||||||
|
|
||||||
var pageFolders = folders.Select(f => new VaultListPageModel.Folder(f,
|
|
||||||
sites.Where(s => s.FolderId == f.Id))).OrderBy(f => f.Name).ToList();
|
|
||||||
var noneFolder = new VaultListPageModel.Folder(sites.Where(s => s.FolderId == null));
|
var noneFolder = new VaultListPageModel.Folder(sites.Where(s => s.FolderId == null));
|
||||||
pageFolders.Add(noneFolder);
|
folders.Add(noneFolder);
|
||||||
|
|
||||||
Folders.ResetWithRange(pageFolders.Where(f => f.Any()));
|
PresentationFolders.ResetWithRange(folders.Where(f => f.Any()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SiteSelected(object sender, SelectedItemChangedEventArgs e)
|
private void SiteSelected(object sender, SelectedItemChangedEventArgs e)
|
||||||
|
@ -182,7 +251,7 @@ namespace Bit.App.Pages
|
||||||
|
|
||||||
if(deleteCall.Succeeded)
|
if(deleteCall.Succeeded)
|
||||||
{
|
{
|
||||||
var folder = Folders.Single(f => f.Id == site.FolderId);
|
var folder = PresentationFolders.Single(f => f.Id == site.FolderId);
|
||||||
var siteIndex = folder.Select((s, i) => new { s, i }).First(s => s.s.Id == site.Id).i;
|
var siteIndex = folder.Select((s, i) => new { s, i }).First(s => s.s.Id == site.Id).i;
|
||||||
folder.RemoveAt(siteIndex);
|
folder.RemoveAt(siteIndex);
|
||||||
_userDialogs.SuccessToast(AppResources.SiteDeleted);
|
_userDialogs.SuccessToast(AppResources.SiteDeleted);
|
||||||
|
|
Loading…
Reference in a new issue