stub out autofill ciphers listing page

This commit is contained in:
Kyle Spearrin 2019-05-17 13:14:26 -04:00
parent d53bfae529
commit 3e633dc38e
7 changed files with 262 additions and 3 deletions

View file

@ -57,6 +57,9 @@
<Compile Update="Pages\Vault\AttachmentsPage.xaml.cs"> <Compile Update="Pages\Vault\AttachmentsPage.xaml.cs">
<DependentUpon>AttachmentsPage.xaml</DependentUpon> <DependentUpon>AttachmentsPage.xaml</DependentUpon>
</Compile> </Compile>
<Compile Update="Pages\Vault\AutofillCiphersPage.xaml.cs">
<DependentUpon>AutofillCiphersPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Vault\CollectionsPage.xaml.cs"> <Compile Update="Pages\Vault\CollectionsPage.xaml.cs">
<DependentUpon>CollectionsPage.xaml</DependentUpon> <DependentUpon>CollectionsPage.xaml</DependentUpon>
</Compile> </Compile>

View file

@ -180,6 +180,10 @@ namespace Bit.App
{ {
Current.MainPage = new NavigationPage(new AddEditPage(appOptions: _appOptions)); Current.MainPage = new NavigationPage(new AddEditPage(appOptions: _appOptions));
} }
else if(_appOptions.Uri != null)
{
Current.MainPage = new NavigationPage(new AutofillCiphersPage(_appOptions));
}
else else
{ {
Current.MainPage = new TabsPage(); Current.MainPage = new TabsPage();

View file

@ -0,0 +1,96 @@
<?xml version="1.0" encoding="utf-8" ?>
<pages:BaseContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="Bit.App.Pages.AutofillCiphersPage"
xmlns:pages="clr-namespace:Bit.App.Pages"
xmlns:u="clr-namespace:Bit.App.Utilities"
xmlns:controls="clr-namespace:Bit.App.Controls"
xmlns:fab="clr-namespace:Refractored.FabControl;assembly=Refractored.FabControl"
x:DataType="pages:AutofillCiphersPageViewModel"
Title="{Binding PageTitle}"
x:Name="_page">
<ContentPage.BindingContext>
<pages:AutofillCiphersPageViewModel />
</ContentPage.BindingContext>
<ContentPage.ToolbarItems>
<ToolbarItem Text="&#xf002;" Clicked="Search_Clicked" />
</ContentPage.ToolbarItems>
<ContentPage.Resources>
<ResourceDictionary>
<DataTemplate x:Key="cipherTemplate"
x:DataType="pages:GroupingsPageListItem">
<controls:CipherViewCell
Cipher="{Binding Cipher}"
ButtonCommand="{Binding BindingContext.CipherOptionsCommand, Source={x:Reference _page}}" />
</DataTemplate>
<pages:GroupingsPageListItemSelector x:Key="listItemDataTemplateSelector"
CipherTemplate="{StaticResource cipherTemplate}" />
<StackLayout x:Key="mainLayout" x:Name="_mainLayout">
<StackLayout
VerticalOptions="CenterAndExpand"
Padding="20, 0"
Spacing="20"
IsVisible="{Binding ShowNoData}">
<Label
Text="TODO: no data"
HorizontalTextAlignment="Center"></Label>
<Button
Text="{u:I18n AddAnItem}"
Clicked="AddButton_Clicked"></Button>
</StackLayout>
<controls:ExtendedListView
IsVisible="{Binding ShowList}"
ItemsSource="{Binding GroupedItems}"
VerticalOptions="FillAndExpand"
HasUnevenRows="true"
ItemTemplate="{StaticResource listItemDataTemplateSelector}"
IsGroupingEnabled="True"
ItemSelected="RowSelected"
StyleClass="list, list-platform">
<x:Arguments>
<ListViewCachingStrategy>RecycleElement</ListViewCachingStrategy>
</x:Arguments>
<ListView.GroupHeaderTemplate>
<DataTemplate x:DataType="pages:GroupingsPageListGroup">
<ViewCell>
<StackLayout StyleClass="list-row-header">
<Label
Text="{Binding Name}"
StyleClass="list-header, list-header-platform" />
<Label
Text="{Binding ItemCount}"
StyleClass="list-header-sub" />
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.GroupHeaderTemplate>
</controls:ExtendedListView>
</StackLayout>
</ResourceDictionary>
</ContentPage.Resources>
<AbsoluteLayout
x:Name="_absLayout"
VerticalOptions="FillAndExpand"
HorizontalOptions="FillAndExpand">
<ContentView
x:Name="_mainContent"
AbsoluteLayout.LayoutFlags="All"
AbsoluteLayout.LayoutBounds="0, 0, 1, 1">
</ContentView>
<fab:FloatingActionButtonView
x:Name="_fab"
ImageName="plus.png"
AbsoluteLayout.LayoutFlags="PositionProportional"
AbsoluteLayout.LayoutBounds="1, 1, AutoSize, AutoSize">
</fab:FloatingActionButtonView>
</AbsoluteLayout>
</pages:BaseContentPage>

View file

@ -0,0 +1,53 @@
using Bit.App.Models;
using Xamarin.Forms;
namespace Bit.App.Pages
{
public partial class AutofillCiphersPage : BaseContentPage
{
private AutofillCiphersPageViewModel _vm;
private readonly AppOptions _appOptions;
public AutofillCiphersPage(AppOptions appOptions)
{
_appOptions = appOptions;
InitializeComponent();
_vm = BindingContext as AutofillCiphersPageViewModel;
_vm.Page = this;
_vm.Init(appOptions);
}
protected async override void OnAppearing()
{
base.OnAppearing();
await LoadOnAppearedAsync(_mainLayout, false, async () =>
{
await _vm.LoadAsync();
}, _mainContent);
}
private async void RowSelected(object sender, SelectedItemChangedEventArgs e)
{
((ListView)sender).SelectedItem = null;
if(!DoOnce())
{
return;
}
if(e.SelectedItem is GroupingsPageListItem item && item.Cipher != null)
{
// TODO
}
}
private void AddButton_Clicked(object sender, System.EventArgs e)
{
}
private void Search_Clicked(object sender, System.EventArgs e)
{
}
}
}

View file

@ -0,0 +1,105 @@
using Bit.App.Models;
using Bit.App.Resources;
using Bit.Core;
using Bit.Core.Abstractions;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace Bit.App.Pages
{
public class AutofillCiphersPageViewModel : BaseViewModel
{
private readonly IPlatformUtilsService _platformUtilsService;
private readonly ICipherService _cipherService;
private readonly ISearchService _searchService;
private CancellationTokenSource _searchCancellationTokenSource;
private AppOptions _appOptions;
private string _name;
private string _uri;
private bool _showNoData;
private bool _showList;
public AutofillCiphersPageViewModel()
{
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
_searchService = ServiceContainer.Resolve<ISearchService>("searchService");
GroupedItems = new ExtendedObservableCollection<GroupingsPageListGroup>();
CipherOptionsCommand = new Command<CipherView>(CipherOptionsAsync);
}
public Command CipherOptionsCommand { get; set; }
public ExtendedObservableCollection<GroupingsPageListGroup> GroupedItems { get; set; }
public bool ShowNoData
{
get => _showNoData;
set => SetProperty(ref _showNoData, value);
}
public bool ShowList
{
get => _showList;
set => SetProperty(ref _showList, value);
}
public void Init(AppOptions appOptions)
{
_appOptions = appOptions;
_uri = appOptions.Uri;
if(_uri.StartsWith(Constants.AndroidAppProtocol))
{
_name = _uri.Substring(Constants.AndroidAppProtocol.Length);
}
else if(!Uri.TryCreate(_uri, UriKind.Absolute, out Uri uri) ||
!DomainName.TryParseBaseDomain(uri.Host, out _name))
{
_name = "--";
}
PageTitle = string.Format(AppResources.ItemsForUri, _name ?? "--");
}
public async Task LoadAsync()
{
ShowNoData = false;
ShowList = false;
var ciphers = await _cipherService.GetAllDecryptedByUrlAsync(_uri, null);
var matching = ciphers.Item1?.Select(c => new GroupingsPageListItem { Cipher = c }).ToList();
var matchingGroup = new GroupingsPageListGroup(matching, AppResources.MatchingItems, matching.Count, false);
var fuzzy = ciphers.Item2?.Select(c => new GroupingsPageListItem { Cipher = c }).ToList();
var fuzzyGroup = new GroupingsPageListGroup(fuzzy, AppResources.PossibleMatchingItems, fuzzy.Count, false);
GroupedItems.ResetWithRange(new List<GroupingsPageListGroup> { matchingGroup, fuzzyGroup });
ShowNoData = !matching.Any() && !fuzzy.Any();
ShowList = !ShowNoData;
}
public async Task SelectCipherAsync(CipherView cipher)
{
// TODO
}
private async void CipherOptionsAsync(CipherView cipher)
{
if(!(Page as BaseContentPage).DoOnce())
{
return;
}
var option = await Page.DisplayActionSheet(cipher.Name, AppResources.Cancel, null, "1", "2");
if(option == AppResources.Cancel)
{
return;
}
// TODO: process options
}
}
}

View file

@ -64,7 +64,7 @@
HorizontalTextAlignment="Center"></Label> HorizontalTextAlignment="Center"></Label>
<Button <Button
Text="{u:I18n AddAnItem}" Text="{u:I18n AddAnItem}"
Command="{Binding AddCipherCommand}" Clicked="AddButton_Clicked"
IsVisible="{Binding ShowAddCipherButton}"></Button> IsVisible="{Binding ShowAddCipherButton}"></Button>
</StackLayout> </StackLayout>

View file

@ -46,7 +46,6 @@ namespace Bit.App.Pages
Refreshing = true; Refreshing = true;
await LoadAsync(); await LoadAsync();
}); });
AddCipherCommand = new Command(() => { /* TODO */ });
CipherOptionsCommand = new Command<CipherView>(CipherOptionsAsync); CipherOptionsCommand = new Command<CipherView>(CipherOptionsAsync);
} }
@ -104,7 +103,6 @@ namespace Bit.App.Pages
} }
public ExtendedObservableCollection<GroupingsPageListGroup> GroupedItems { get; set; } public ExtendedObservableCollection<GroupingsPageListGroup> GroupedItems { get; set; }
public Command RefreshCommand { get; set; } public Command RefreshCommand { get; set; }
public Command AddCipherCommand { get; set; }
public Command<CipherView> CipherOptionsCommand { get; set; } public Command<CipherView> CipherOptionsCommand { get; set; }
public async Task LoadAsync() public async Task LoadAsync()