mirror of
https://github.com/bitwarden/mobile.git
synced 2024-11-24 11:55:38 +01:00
vault groupings page list view stubbed
This commit is contained in:
parent
d84eece715
commit
69ac98b2f6
@ -1,38 +1,15 @@
|
|||||||
using System;
|
using Bit.Core.Utilities;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public abstract class BaseViewModel : INotifyPropertyChanged
|
public abstract class BaseViewModel : ExtendedViewModel
|
||||||
{
|
{
|
||||||
private string _pageTitle = string.Empty;
|
private string _pageTitle = string.Empty;
|
||||||
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
|
||||||
|
|
||||||
public string PageTitle
|
public string PageTitle
|
||||||
{
|
{
|
||||||
get => _pageTitle;
|
get => _pageTitle;
|
||||||
set => SetProperty(ref _pageTitle, value);
|
set => SetProperty(ref _pageTitle, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected bool SetProperty<T>(ref T backingStore, T value, [CallerMemberName]string propertyName = "",
|
|
||||||
Action onChanged = null)
|
|
||||||
{
|
|
||||||
if(EqualityComparer<T>.Default.Equals(backingStore, value))
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
backingStore = value;
|
|
||||||
onChanged?.Invoke();
|
|
||||||
OnPropertyChanged(propertyName);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
|
|
||||||
{
|
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,27 +6,72 @@
|
|||||||
xmlns:pages="clr-namespace:Bit.App.Pages"
|
xmlns:pages="clr-namespace:Bit.App.Pages"
|
||||||
x:DataType="pages:VaultGroupingsPageViewModel"
|
x:DataType="pages:VaultGroupingsPageViewModel"
|
||||||
Title="{Binding PageTitle}">
|
Title="{Binding PageTitle}">
|
||||||
|
|
||||||
<ContentPage.BindingContext>
|
<ContentPage.BindingContext>
|
||||||
<pages:VaultGroupingsPageViewModel />
|
<pages:VaultGroupingsPageViewModel />
|
||||||
</ContentPage.BindingContext>
|
</ContentPage.BindingContext>
|
||||||
|
|
||||||
<StackLayout>
|
<ContentPage.Resources>
|
||||||
<!-- Place new controls here -->
|
<ResourceDictionary>
|
||||||
<Label
|
<DataTemplate
|
||||||
Text="Vault Groupings!"
|
x:Key="cipherTemplate"
|
||||||
HorizontalOptions="Center"
|
x:DataType="pages:VaultGroupingsPageListItem">
|
||||||
VerticalOptions="CenterAndExpand" />
|
<ViewCell>
|
||||||
<Label
|
<StackLayout Padding="10">
|
||||||
Text=""
|
<Label
|
||||||
HorizontalOptions="Center"
|
Text="{Binding Cipher.Name}"
|
||||||
VerticalOptions="CenterAndExpand">
|
LineBreakMode="NoWrap"
|
||||||
|
FontSize="16" />
|
||||||
|
</StackLayout>
|
||||||
|
</ViewCell>
|
||||||
|
</DataTemplate>
|
||||||
|
|
||||||
<Label.FontFamily>
|
<DataTemplate
|
||||||
<OnPlatform x:TypeArguments="x:String"
|
x:Key="folderTemplate"
|
||||||
Android="FontAwesome.ttf#FontAwesome"
|
x:DataType="pages:VaultGroupingsPageListItem">
|
||||||
iOS="FontAwesome" />
|
<ViewCell>
|
||||||
</Label.FontFamily>
|
<StackLayout Padding="10">
|
||||||
</Label>
|
<Label
|
||||||
|
Text="{Binding Folder.Name}"
|
||||||
|
LineBreakMode="NoWrap"
|
||||||
|
FontSize="16" />
|
||||||
|
</StackLayout>
|
||||||
|
</ViewCell>
|
||||||
|
</DataTemplate>
|
||||||
|
|
||||||
|
<DataTemplate
|
||||||
|
x:Key="collectionTemplate"
|
||||||
|
x:DataType="pages:VaultGroupingsPageListItem">
|
||||||
|
<ViewCell>
|
||||||
|
<StackLayout Padding="10">
|
||||||
|
<Label
|
||||||
|
Text="{Binding Collection.Name}"
|
||||||
|
LineBreakMode="NoWrap"
|
||||||
|
FontSize="16" />
|
||||||
|
</StackLayout>
|
||||||
|
</ViewCell>
|
||||||
|
</DataTemplate>
|
||||||
|
|
||||||
|
<pages:ListItemDataTemplateSelector
|
||||||
|
x:Key="listItemDataTemplateSelector"
|
||||||
|
CipherTemplate="{StaticResource cipherTemplate}"
|
||||||
|
FolderTemplate="{StaticResource folderTemplate}"
|
||||||
|
CollectionTemplate="{StaticResource collectionTemplate}" />
|
||||||
|
</ResourceDictionary>
|
||||||
|
</ContentPage.Resources>
|
||||||
|
|
||||||
|
<StackLayout>
|
||||||
|
<ListView
|
||||||
|
x:Name="ItemsListView"
|
||||||
|
ItemsSource="{Binding Items}"
|
||||||
|
VerticalOptions="FillAndExpand"
|
||||||
|
HasUnevenRows="true"
|
||||||
|
RefreshCommand="{Binding LoadCommand}"
|
||||||
|
IsPullToRefreshEnabled="true"
|
||||||
|
IsRefreshing="{Binding Loading, Mode=OneWay}"
|
||||||
|
CachingStrategy="RecycleElement"
|
||||||
|
ItemTemplate="{StaticResource listItemDataTemplateSelector}">
|
||||||
|
</ListView>
|
||||||
</StackLayout>
|
</StackLayout>
|
||||||
|
|
||||||
</ContentPage>
|
</ContentPage>
|
||||||
|
@ -10,9 +10,42 @@ namespace Bit.App.Pages
|
|||||||
{
|
{
|
||||||
public partial class VaultGroupingsPage : ContentPage
|
public partial class VaultGroupingsPage : ContentPage
|
||||||
{
|
{
|
||||||
|
private VaultGroupingsPageViewModel _viewModel;
|
||||||
|
|
||||||
public VaultGroupingsPage()
|
public VaultGroupingsPage()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
_viewModel = BindingContext as VaultGroupingsPageViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected async override void OnAppearing()
|
||||||
|
{
|
||||||
|
base.OnAppearing();
|
||||||
|
await _viewModel.LoadAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ListItemDataTemplateSelector : DataTemplateSelector
|
||||||
|
{
|
||||||
|
public DataTemplate CipherTemplate { get; set; }
|
||||||
|
public DataTemplate FolderTemplate { get; set; }
|
||||||
|
public DataTemplate CollectionTemplate { get; set; }
|
||||||
|
|
||||||
|
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
|
||||||
|
{
|
||||||
|
if(item is VaultGroupingsPageListItem listItem)
|
||||||
|
{
|
||||||
|
if(listItem.Collection != null)
|
||||||
|
{
|
||||||
|
return CollectionTemplate;
|
||||||
|
}
|
||||||
|
else if(listItem.Folder != null)
|
||||||
|
{
|
||||||
|
return FolderTemplate;
|
||||||
|
}
|
||||||
|
return CipherTemplate;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,93 @@
|
|||||||
using System;
|
using Bit.Core.Models.View;
|
||||||
|
using Bit.Core.Utilities;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text;
|
using System.Threading.Tasks;
|
||||||
|
using Xamarin.Forms;
|
||||||
|
|
||||||
namespace Bit.App.Pages
|
namespace Bit.App.Pages
|
||||||
{
|
{
|
||||||
public class VaultGroupingsPageViewModel : BaseViewModel
|
public class VaultGroupingsPageViewModel : BaseViewModel
|
||||||
{
|
{
|
||||||
|
private bool _loading = false;
|
||||||
|
|
||||||
public VaultGroupingsPageViewModel()
|
public VaultGroupingsPageViewModel()
|
||||||
{
|
{
|
||||||
PageTitle = "My Vault";
|
PageTitle = "My Vault";
|
||||||
|
Items = new ExtendedObservableCollection<VaultGroupingsPageListItem>();
|
||||||
|
LoadCommand = new Command(async () => await LoadAsync());
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool Loading
|
||||||
|
{
|
||||||
|
get => _loading;
|
||||||
|
set => SetProperty(ref _loading, value);
|
||||||
|
}
|
||||||
|
public ExtendedObservableCollection<VaultGroupingsPageListItem> Items { get; set; }
|
||||||
|
public Command LoadCommand { get; set; }
|
||||||
|
|
||||||
|
public Task LoadAsync()
|
||||||
|
{
|
||||||
|
if(Loading)
|
||||||
|
{
|
||||||
|
return Task.FromResult(0);
|
||||||
|
}
|
||||||
|
Loading = true;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
Items.ResetWithRange(new List<VaultGroupingsPageListItem>
|
||||||
|
{
|
||||||
|
new VaultGroupingsPageListItem
|
||||||
|
{
|
||||||
|
Cipher = new CipherView { Name = "Cipher 1" }
|
||||||
|
},
|
||||||
|
new VaultGroupingsPageListItem
|
||||||
|
{
|
||||||
|
Cipher = new CipherView { Name = "Cipher 2" }
|
||||||
|
},
|
||||||
|
new VaultGroupingsPageListItem
|
||||||
|
{
|
||||||
|
Cipher = new CipherView { Name = "Cipher 3" }
|
||||||
|
},
|
||||||
|
new VaultGroupingsPageListItem
|
||||||
|
{
|
||||||
|
Cipher = new CipherView { Name = "Cipher 4" }
|
||||||
|
},
|
||||||
|
new VaultGroupingsPageListItem
|
||||||
|
{
|
||||||
|
Folder = new FolderView { Name = "Folder 1" }
|
||||||
|
},
|
||||||
|
new VaultGroupingsPageListItem
|
||||||
|
{
|
||||||
|
Folder = new FolderView { Name = "Folder 2" }
|
||||||
|
},
|
||||||
|
new VaultGroupingsPageListItem
|
||||||
|
{
|
||||||
|
Folder = new FolderView { Name = "Folder 3" }
|
||||||
|
},
|
||||||
|
new VaultGroupingsPageListItem
|
||||||
|
{
|
||||||
|
Collection = new Core.Models.View.CollectionView { Name = "Collection 1" }
|
||||||
|
},
|
||||||
|
new VaultGroupingsPageListItem
|
||||||
|
{
|
||||||
|
Collection = new Core.Models.View.CollectionView { Name = "Collection 2" }
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
Loading = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Task.FromResult(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public class VaultGroupingsPageListItem
|
||||||
|
{
|
||||||
|
public FolderView Folder { get; set; }
|
||||||
|
public Core.Models.View.CollectionView Collection { get; set; }
|
||||||
|
public CipherView Cipher { get; set; }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
12
src/Core/Models/View/CipherView.cs
Normal file
12
src/Core/Models/View/CipherView.cs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.View
|
||||||
|
{
|
||||||
|
public class CipherView
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Subtitle { get; set; }
|
||||||
|
}
|
||||||
|
}
|
10
src/Core/Models/View/CollectionView.cs
Normal file
10
src/Core/Models/View/CollectionView.cs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
using System;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.View
|
||||||
|
{
|
||||||
|
public class CollectionView
|
||||||
|
{
|
||||||
|
public Guid OrganizationId { get; set; }
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
11
src/Core/Models/View/FolderView.cs
Normal file
11
src/Core/Models/View/FolderView.cs
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Bit.Core.Models.View
|
||||||
|
{
|
||||||
|
public class FolderView
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
}
|
||||||
|
}
|
37
src/Core/Utilities/ExtendedObservableCollection.cs
Normal file
37
src/Core/Utilities/ExtendedObservableCollection.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Collections.Specialized;
|
||||||
|
using System.ComponentModel;
|
||||||
|
|
||||||
|
namespace Bit.Core.Utilities
|
||||||
|
{
|
||||||
|
public class ExtendedObservableCollection<T> : ObservableCollection<T>
|
||||||
|
{
|
||||||
|
public ExtendedObservableCollection()
|
||||||
|
: base() { }
|
||||||
|
|
||||||
|
public ExtendedObservableCollection(IEnumerable<T> collection)
|
||||||
|
: base(collection) { }
|
||||||
|
|
||||||
|
public ExtendedObservableCollection(List<T> list)
|
||||||
|
: base(list) { }
|
||||||
|
|
||||||
|
public void AddRange(IEnumerable<T> range)
|
||||||
|
{
|
||||||
|
foreach(var item in range)
|
||||||
|
{
|
||||||
|
Items.Add(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
OnPropertyChanged(new PropertyChangedEventArgs("Count"));
|
||||||
|
OnPropertyChanged(new PropertyChangedEventArgs("Item[]"));
|
||||||
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ResetWithRange(IEnumerable<T> range)
|
||||||
|
{
|
||||||
|
Items.Clear();
|
||||||
|
AddRange(range);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
31
src/Core/Utilities/ExtendedViewModel.cs
Normal file
31
src/Core/Utilities/ExtendedViewModel.cs
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace Bit.Core.Utilities
|
||||||
|
{
|
||||||
|
public abstract class ExtendedViewModel : INotifyPropertyChanged
|
||||||
|
{
|
||||||
|
public event PropertyChangedEventHandler PropertyChanged;
|
||||||
|
|
||||||
|
protected bool SetProperty<T>(ref T backingStore, T value, [CallerMemberName]string propertyName = "",
|
||||||
|
Action onChanged = null)
|
||||||
|
{
|
||||||
|
if(EqualityComparer<T>.Default.Equals(backingStore, value))
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
backingStore = value;
|
||||||
|
onChanged?.Invoke();
|
||||||
|
OnPropertyChanged(propertyName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
|
||||||
|
{
|
||||||
|
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user