collections page

This commit is contained in:
Kyle Spearrin 2019-05-10 14:28:17 -04:00
parent 253217cf20
commit 2b2787b187
7 changed files with 191 additions and 5 deletions

View file

@ -38,6 +38,9 @@
<Compile Update="Pages\Generator\GeneratorPage.xaml.cs"> <Compile Update="Pages\Generator\GeneratorPage.xaml.cs">
<DependentUpon>GeneratorPage.xaml</DependentUpon> <DependentUpon>GeneratorPage.xaml</DependentUpon>
</Compile> </Compile>
<Compile Update="Pages\Vault\CollectionsPage.xaml.cs">
<DependentUpon>CollectionsPage.xaml</DependentUpon>
</Compile>
<Compile Update="Pages\Vault\SharePage.xaml.cs"> <Compile Update="Pages\Vault\SharePage.xaml.cs">
<DependentUpon>SharePage.xaml</DependentUpon> <DependentUpon>SharePage.xaml</DependentUpon>
</Compile> </Compile>

View file

@ -124,11 +124,12 @@ namespace Bit.App.Pages
} }
} }
private void Collections_Clicked(object sender, System.EventArgs e) private async void Collections_Clicked(object sender, System.EventArgs e)
{ {
if(DoOnce()) if(DoOnce())
{ {
// TODO var page = new CollectionsPage(_vm.CipherId);
await Navigation.PushModalAsync(new NavigationPage(page));
} }
} }
} }

View file

@ -0,0 +1,57 @@
<?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.CollectionsPage"
xmlns:pages="clr-namespace:Bit.App.Pages"
xmlns:u="clr-namespace:Bit.App.Utilities"
xmlns:controls="clr-namespace:Bit.App.Controls"
x:DataType="pages:CollectionsPageViewModel"
x:Name="_page"
Title="{Binding PageTitle}">
<ContentPage.BindingContext>
<pages:CollectionsPageViewModel />
</ContentPage.BindingContext>
<ContentPage.ToolbarItems>
<ToolbarItem Text="{u:I18n Save}" Clicked="Save_Clicked" />
</ContentPage.ToolbarItems>
<ContentPage.Resources>
<ResourceDictionary>
<u:InverseBoolConverter x:Key="inverseBool" />
<u:IsNotNullConverter x:Key="notNull" />
</ResourceDictionary>
</ContentPage.Resources>
<ScrollView x:Name="_scrollView">
<StackLayout Spacing="20">
<StackLayout StyleClass="box">
<StackLayout StyleClass="box-row"
IsVisible="{Binding HasCollections, Converter={StaticResource inverseBool}}">
<Label Text="{u:I18n NoCollectionsToList}" />
</StackLayout>
<controls:RepeaterView ItemsSource="{Binding Collections}" IsVisible="{Binding HasCollections}">
<controls:RepeaterView.ItemTemplate>
<DataTemplate x:DataType="pages:CollectionViewModel">
<StackLayout Spacing="0" Padding="0">
<StackLayout StyleClass="box-row, box-row-switch">
<Label
Text="{Binding Collection.Name}"
StyleClass="box-label, box-label-regular"
HorizontalOptions="StartAndExpand" />
<Switch
IsToggled="{Binding Checked}"
StyleClass="box-value"
HorizontalOptions="End" />
</StackLayout>
<BoxView StyleClass="box-row-separator" />
</StackLayout>
</DataTemplate>
</controls:RepeaterView.ItemTemplate>
</controls:RepeaterView>
</StackLayout>
</StackLayout>
</ScrollView>
</pages:BaseContentPage>

View file

@ -0,0 +1,37 @@
using Xamarin.Forms;
namespace Bit.App.Pages
{
public partial class CollectionsPage : BaseContentPage
{
private CollectionsPageViewModel _vm;
public CollectionsPage(string cipherId)
{
InitializeComponent();
_vm = BindingContext as CollectionsPageViewModel;
_vm.Page = this;
_vm.CipherId = cipherId;
SetActivityIndicator();
}
protected override async void OnAppearing()
{
base.OnAppearing();
await LoadOnAppearedAsync(_scrollView, true, () => _vm.LoadAsync());
}
protected override void OnDisappearing()
{
base.OnDisappearing();
}
private async void Save_Clicked(object sender, System.EventArgs e)
{
if(DoOnce())
{
await _vm.SubmitAsync();
}
}
}
}

View file

@ -0,0 +1,87 @@
using Bit.App.Abstractions;
using Bit.App.Resources;
using Bit.Core.Abstractions;
using Bit.Core.Exceptions;
using Bit.Core.Models.Domain;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Bit.App.Pages
{
public class CollectionsPageViewModel : BaseViewModel
{
private readonly IDeviceActionService _deviceActionService;
private readonly ICipherService _cipherService;
private readonly ICollectionService _collectionService;
private readonly IPlatformUtilsService _platformUtilsService;
private CipherView _cipher;
private Cipher _cipherDomain;
private bool _hasCollections;
public CollectionsPageViewModel()
{
_deviceActionService = ServiceContainer.Resolve<IDeviceActionService>("deviceActionService");
_cipherService = ServiceContainer.Resolve<ICipherService>("cipherService");
_platformUtilsService = ServiceContainer.Resolve<IPlatformUtilsService>("platformUtilsService");
_collectionService = ServiceContainer.Resolve<ICollectionService>("collectionService");
Collections = new ExtendedObservableCollection<CollectionViewModel>();
PageTitle = AppResources.Collections;
}
public string CipherId { get; set; }
public ExtendedObservableCollection<CollectionViewModel> Collections { get; set; }
public bool HasCollections
{
get => _hasCollections;
set => SetProperty(ref _hasCollections, value);
}
public async Task LoadAsync()
{
_cipherDomain = await _cipherService.GetAsync(CipherId);
var collectionIds = _cipherDomain.CollectionIds;
_cipher = await _cipherDomain.DecryptAsync();
var allCollections = await _collectionService.GetAllDecryptedAsync();
var collections = allCollections
.Where(c => !c.ReadOnly && c.OrganizationId == _cipher.OrganizationId)
.Select(c => new CollectionViewModel
{
Collection = c,
Checked = collectionIds.Contains(c.Id)
}).ToList();
Collections.ResetWithRange(collections);
HasCollections = Collections.Any();
}
public async Task<bool> SubmitAsync()
{
if(!Collections.Any(c => c.Checked))
{
await Page.DisplayAlert(AppResources.AnErrorHasOccurred, AppResources.SelectOneCollection,
AppResources.Ok);
return false;
}
_cipherDomain.CollectionIds = new HashSet<string>(
Collections.Where(c => c.Checked).Select(c => c.Collection.Id));
try
{
await _deviceActionService.ShowLoadingAsync(AppResources.Saving);
await _cipherService.SaveCollectionsWithServerAsync(_cipherDomain);
await _deviceActionService.HideLoadingAsync();
_platformUtilsService.ShowToast("success", null, AppResources.ItemUpdated);
await Page.Navigation.PopModalAsync();
return true;
}
catch(ApiException e)
{
await _deviceActionService.HideLoadingAsync();
await Page.DisplayAlert(AppResources.AnErrorHasOccurred, e.Error.GetSingleMessage(), AppResources.Ok);
}
return false;
}
}
}

View file

@ -6,7 +6,7 @@ namespace Bit.App.Pages
{ {
private SharePageViewModel _vm; private SharePageViewModel _vm;
public SharePage(string cipherId = null) public SharePage(string cipherId)
{ {
InitializeComponent(); InitializeComponent();
_vm = BindingContext as SharePageViewModel; _vm = BindingContext as SharePageViewModel;

View file

@ -130,11 +130,12 @@ namespace Bit.App.Pages
} }
} }
private void Collections_Clicked(object sender, System.EventArgs e) private async void Collections_Clicked(object sender, System.EventArgs e)
{ {
if(DoOnce()) if(DoOnce())
{ {
// TODO var page = new CollectionsPage(_vm.CipherId);
await Navigation.PushModalAsync(new NavigationPage(page));
} }
} }
} }