mirror of
https://github.com/bitwarden/android.git
synced 2024-12-25 02:18:27 +03:00
stub out autofill ciphers listing page
This commit is contained in:
parent
d53bfae529
commit
3e633dc38e
7 changed files with 262 additions and 3 deletions
|
@ -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>
|
||||||
|
|
|
@ -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();
|
||||||
|
|
96
src/App/Pages/Vault/AutofillCiphersPage.xaml
Normal file
96
src/App/Pages/Vault/AutofillCiphersPage.xaml
Normal 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="" 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>
|
53
src/App/Pages/Vault/AutofillCiphersPage.xaml.cs
Normal file
53
src/App/Pages/Vault/AutofillCiphersPage.xaml.cs
Normal 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)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
105
src/App/Pages/Vault/AutofillCiphersPageViewModel.cs
Normal file
105
src/App/Pages/Vault/AutofillCiphersPageViewModel.cs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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()
|
||||||
|
|
Loading…
Reference in a new issue