consolidating section header models

This commit is contained in:
Kyle Spearrin 2017-11-25 23:32:20 -05:00
parent 362ddd0339
commit 2f2d85576f
4 changed files with 48 additions and 63 deletions

View file

@ -183,30 +183,25 @@ namespace Bit.App.Models.Page
public string Name { get; set; } = AppResources.FolderNone; public string Name { get; set; } = AppResources.FolderNone;
} }
public class NameGroup : List<Cipher> public class Section<T> : List<T>
{ {
public NameGroup(string nameGroup, List<Cipher> ciphers) public Section(List<T> groupItems, string name, bool doUpper = true)
{ {
Name = nameGroup.ToUpperInvariant(); AddRange(groupItems);
AddRange(ciphers);
if(doUpper)
{
Name = name.ToUpperInvariant();
}
else
{
Name = name;
}
} }
public string Name { get; set; } public string Name { get; set; }
} }
public class Section : List<Grouping>
{
public Section(List<Grouping> groupings, string name)
{
AddRange(groupings);
Name = name.ToUpperInvariant();
ItemCount = groupings.Count;
}
public string Name { get; set; }
public int ItemCount { get; set; }
}
public class Grouping public class Grouping
{ {
public Grouping(string name, int count) public Grouping(string name, int count)
@ -239,16 +234,5 @@ namespace Bit.App.Models.Page
public bool Folder { get; set; } public bool Folder { get; set; }
public bool Collection { get; set; } public bool Collection { get; set; }
} }
public class AutofillGrouping : List<AutofillCipher>
{
public AutofillGrouping(List<AutofillCipher> logins, string name)
{
AddRange(logins);
Name = name;
}
public string Name { get; set; }
}
} }
} }

View file

@ -13,6 +13,7 @@ using System.Threading;
using Bit.App.Models; using Bit.App.Models;
using System.Collections.Generic; using System.Collections.Generic;
using Bit.App.Enums; using Bit.App.Enums;
using static Bit.App.Models.Page.VaultListPageModel;
namespace Bit.App.Pages namespace Bit.App.Pages
{ {
@ -53,8 +54,8 @@ namespace Bit.App.Pages
Init(); Init();
} }
public ExtendedObservableCollection<VaultListPageModel.AutofillGrouping> PresentationCiphersGroup { get; private set; } public ExtendedObservableCollection<Section<AutofillCipher>> PresentationCiphersGroup { get; private set; }
= new ExtendedObservableCollection<VaultListPageModel.AutofillGrouping>(); = new ExtendedObservableCollection<Section<AutofillCipher>>();
public StackLayout NoDataStackLayout { get; set; } public StackLayout NoDataStackLayout { get; set; }
public ListView ListView { get; set; } public ListView ListView { get; set; }
public ActivityIndicator LoadingIndicator { get; set; } public ActivityIndicator LoadingIndicator { get; set; }
@ -100,7 +101,7 @@ namespace Bit.App.Pages
ItemsSource = PresentationCiphersGroup, ItemsSource = PresentationCiphersGroup,
HasUnevenRows = true, HasUnevenRows = true,
GroupHeaderTemplate = new DataTemplate(() => new SectionHeaderViewCell( GroupHeaderTemplate = new DataTemplate(() => new SectionHeaderViewCell(
nameof(VaultListPageModel.AutofillGrouping.Name))), nameof(Section<AutofillCipher>.Name))),
ItemTemplate = new DataTemplate(() => new VaultListViewCell( ItemTemplate = new DataTemplate(() => new VaultListViewCell(
(VaultListPageModel.Cipher c) => Helpers.CipherMoreClickedAsync(this, c, true))) (VaultListPageModel.Cipher c) => Helpers.CipherMoreClickedAsync(this, c, true)))
}; };
@ -165,42 +166,42 @@ namespace Bit.App.Pages
Task.Run(async () => Task.Run(async () =>
{ {
var autofillGroupings = new List<VaultListPageModel.AutofillGrouping>(); var autofillGroupings = new List<Section<AutofillCipher>>();
var ciphers = await _cipherService.GetAllAsync(Uri); var ciphers = await _cipherService.GetAllAsync(Uri);
if(_appOptions.FillType.HasValue && _appOptions.FillType.Value != CipherType.Login) if(_appOptions.FillType.HasValue && _appOptions.FillType.Value != CipherType.Login)
{ {
var others = ciphers?.Item3.Where(c => c.Type == _appOptions.FillType.Value) var others = ciphers?.Item3.Where(c => c.Type == _appOptions.FillType.Value)
.Select(c => new VaultListPageModel.AutofillCipher(c, _appSettingsService, false)) .Select(c => new AutofillCipher(c, _appSettingsService, false))
.OrderBy(s => s.Name) .OrderBy(s => s.Name)
.ThenBy(s => s.Subtitle) .ThenBy(s => s.Subtitle)
.ToList(); .ToList();
if(others?.Any() ?? false) if(others?.Any() ?? false)
{ {
autofillGroupings.Add(new VaultListPageModel.AutofillGrouping(others, AppResources.Items)); autofillGroupings.Add(new Section<AutofillCipher>(others, AppResources.Items));
} }
} }
else else
{ {
var normalLogins = ciphers?.Item1 var normalLogins = ciphers?.Item1
.Select(l => new VaultListPageModel.AutofillCipher(l, _appSettingsService, false)) .Select(l => new AutofillCipher(l, _appSettingsService, false))
.OrderBy(s => s.Name) .OrderBy(s => s.Name)
.ThenBy(s => s.Subtitle) .ThenBy(s => s.Subtitle)
.ToList(); .ToList();
if(normalLogins?.Any() ?? false) if(normalLogins?.Any() ?? false)
{ {
autofillGroupings.Add(new VaultListPageModel.AutofillGrouping(normalLogins, autofillGroupings.Add(new Section<AutofillCipher>(normalLogins,
AppResources.MatchingItems)); AppResources.MatchingItems));
} }
var fuzzyLogins = ciphers?.Item2 var fuzzyLogins = ciphers?.Item2
.Select(l => new VaultListPageModel.AutofillCipher(l, _appSettingsService, true)) .Select(l => new AutofillCipher(l, _appSettingsService, true))
.OrderBy(s => s.Name) .OrderBy(s => s.Name)
.ThenBy(s => s.Subtitle) .ThenBy(s => s.Subtitle)
.ToList(); .ToList();
if(fuzzyLogins?.Any() ?? false) if(fuzzyLogins?.Any() ?? false)
{ {
autofillGroupings.Add(new VaultListPageModel.AutofillGrouping(fuzzyLogins, autofillGroupings.Add(new Section<AutofillCipher>(fuzzyLogins,
AppResources.PossibleMatchingItems)); AppResources.PossibleMatchingItems));
} }
} }
@ -221,7 +222,7 @@ namespace Bit.App.Pages
private async void CipherSelected(object sender, SelectedItemChangedEventArgs e) private async void CipherSelected(object sender, SelectedItemChangedEventArgs e)
{ {
var cipher = e.SelectedItem as VaultListPageModel.AutofillCipher; var cipher = e.SelectedItem as AutofillCipher;
if(cipher == null) if(cipher == null)
{ {
return; return;

View file

@ -4,7 +4,6 @@ using System.Threading.Tasks;
using Acr.UserDialogs; using Acr.UserDialogs;
using Bit.App.Abstractions; using Bit.App.Abstractions;
using Bit.App.Controls; using Bit.App.Controls;
using Bit.App.Models.Page;
using Bit.App.Resources; using Bit.App.Resources;
using Xamarin.Forms; using Xamarin.Forms;
using XLabs.Ioc; using XLabs.Ioc;
@ -14,6 +13,7 @@ using Plugin.Connectivity.Abstractions;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading; using System.Threading;
using Bit.App.Enums; using Bit.App.Enums;
using static Bit.App.Models.Page.VaultListPageModel;
namespace Bit.App.Pages namespace Bit.App.Pages
{ {
@ -52,8 +52,8 @@ namespace Bit.App.Pages
Init(); Init();
} }
public ExtendedObservableCollection<VaultListPageModel.Section> PresentationSections { get; private set; } public ExtendedObservableCollection<Section<Grouping>> PresentationSections { get; private set; }
= new ExtendedObservableCollection<VaultListPageModel.Section>(); = new ExtendedObservableCollection<Section<Grouping>>();
public ListView ListView { get; set; } public ListView ListView { get; set; }
public StackLayout NoDataStackLayout { get; set; } public StackLayout NoDataStackLayout { get; set; }
public ActivityIndicator LoadingIndicator { get; set; } public ActivityIndicator LoadingIndicator { get; set; }
@ -73,7 +73,7 @@ namespace Bit.App.Pages
ItemsSource = PresentationSections, ItemsSource = PresentationSections,
HasUnevenRows = true, HasUnevenRows = true,
GroupHeaderTemplate = new DataTemplate(() => new SectionHeaderViewCell( GroupHeaderTemplate = new DataTemplate(() => new SectionHeaderViewCell(
nameof(VaultListPageModel.Section.Name), nameof(VaultListPageModel.Section.ItemCount), nameof(Section<Grouping>.Name), nameof(Section<Grouping>.Count),
new Thickness(16, Helpers.OnPlatform(20, 12, 12), 16, 12))), new Thickness(16, Helpers.OnPlatform(20, 12, 12), 16, 12))),
ItemTemplate = new DataTemplate(() => new VaultGroupingViewCell()) ItemTemplate = new DataTemplate(() => new VaultGroupingViewCell())
}; };
@ -154,7 +154,7 @@ namespace Bit.App.Pages
Task.Run(async () => Task.Run(async () =>
{ {
var sections = new List<VaultListPageModel.Section>(); var sections = new List<Section<Grouping>>();
var ciphers = await _cipherService.GetAllAsync(); var ciphers = await _cipherService.GetAllAsync();
var collectionsDict = (await _collectionService.GetAllCipherAssociationsAsync()) var collectionsDict = (await _collectionService.GetAllCipherAssociationsAsync())
.GroupBy(c => c.Item2).ToDictionary(g => g.Key, v => v.ToList()); .GroupBy(c => c.Item2).ToDictionary(g => g.Key, v => v.ToList());
@ -178,19 +178,19 @@ namespace Bit.App.Pages
var folders = await _folderService.GetAllAsync(); var folders = await _folderService.GetAllAsync();
var folderGroupings = folders? var folderGroupings = folders?
.Select(f => new VaultListPageModel.Grouping(f, folderCounts.ContainsKey(f.Id) ? folderCounts[f.Id] : 0)) .Select(f => new Grouping(f, folderCounts.ContainsKey(f.Id) ? folderCounts[f.Id] : 0))
.OrderBy(g => g.Name).ToList(); .OrderBy(g => g.Name).ToList();
folderGroupings.Add(new VaultListPageModel.Grouping(AppResources.FolderNone, folderCounts["none"])); folderGroupings.Add(new Grouping(AppResources.FolderNone, folderCounts["none"]));
sections.Add(new VaultListPageModel.Section(folderGroupings, AppResources.Folders)); sections.Add(new Section<Grouping>(folderGroupings, AppResources.Folders));
var collections = await _collectionService.GetAllAsync(); var collections = await _collectionService.GetAllAsync();
var collectionGroupings = collections? var collectionGroupings = collections?
.Select(c => new VaultListPageModel.Grouping(c, .Select(c => new Grouping(c,
collectionsDict.ContainsKey(c.Id) ? collectionsDict[c.Id].Count() : 0)) collectionsDict.ContainsKey(c.Id) ? collectionsDict[c.Id].Count() : 0))
.OrderBy(g => g.Name).ToList(); .OrderBy(g => g.Name).ToList();
if(collectionGroupings?.Any() ?? false) if(collectionGroupings?.Any() ?? false)
{ {
sections.Add(new VaultListPageModel.Section(collectionGroupings, AppResources.Collections)); sections.Add(new Section<Grouping>(collectionGroupings, AppResources.Collections));
} }
Device.BeginInvokeOnMainThread(() => Device.BeginInvokeOnMainThread(() =>
@ -216,7 +216,7 @@ namespace Bit.App.Pages
private void GroupingSelected(object sender, SelectedItemChangedEventArgs e) private void GroupingSelected(object sender, SelectedItemChangedEventArgs e)
{ {
var grouping = e.SelectedItem as VaultListPageModel.Grouping; var grouping = e.SelectedItem as Grouping;
if(grouping == null) if(grouping == null)
{ {
return; return;

View file

@ -3,7 +3,6 @@ using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Bit.App.Abstractions; using Bit.App.Abstractions;
using Bit.App.Controls; using Bit.App.Controls;
using Bit.App.Models.Page;
using Bit.App.Resources; using Bit.App.Resources;
using Xamarin.Forms; using Xamarin.Forms;
using XLabs.Ioc; using XLabs.Ioc;
@ -11,6 +10,7 @@ using Bit.App.Utilities;
using Plugin.Settings.Abstractions; using Plugin.Settings.Abstractions;
using Plugin.Connectivity.Abstractions; using Plugin.Connectivity.Abstractions;
using System.Threading; using System.Threading;
using static Bit.App.Models.Page.VaultListPageModel;
namespace Bit.App.Pages namespace Bit.App.Pages
{ {
@ -39,9 +39,9 @@ namespace Bit.App.Pages
Init(); Init();
} }
public ExtendedObservableCollection<VaultListPageModel.NameGroup> PresentationLetters { get; private set; } public ExtendedObservableCollection<Section<Cipher>> PresentationLetters { get; private set; }
= new ExtendedObservableCollection<VaultListPageModel.NameGroup>(); = new ExtendedObservableCollection<Section<Cipher>>();
public VaultListPageModel.Cipher[] Ciphers { get; set; } = new VaultListPageModel.Cipher[] { }; public Cipher[] Ciphers { get; set; } = new Cipher[] { };
public ListView ListView { get; set; } public ListView ListView { get; set; }
public SearchBar Search { get; set; } public SearchBar Search { get; set; }
public StackLayout ResultsStackLayout { get; set; } public StackLayout ResultsStackLayout { get; set; }
@ -53,10 +53,11 @@ namespace Bit.App.Pages
IsGroupingEnabled = true, IsGroupingEnabled = true,
ItemsSource = PresentationLetters, ItemsSource = PresentationLetters,
HasUnevenRows = true, HasUnevenRows = true,
GroupHeaderTemplate = new DataTemplate(() => new SectionHeaderViewCell( GroupHeaderTemplate = new DataTemplate(() => new SectionHeaderViewCell(nameof(Section<Cipher>.Name),
nameof(VaultListPageModel.NameGroup.Name), nameof(VaultListPageModel.NameGroup.Count))), nameof(Section<Cipher>.Count))),
GroupShortNameBinding = new Binding(nameof(Section<Cipher>.Name)),
ItemTemplate = new DataTemplate(() => new VaultListViewCell( ItemTemplate = new DataTemplate(() => new VaultListViewCell(
(VaultListPageModel.Cipher c) => Helpers.CipherMoreClickedAsync(this, c, false))) (Cipher c) => Helpers.CipherMoreClickedAsync(this, c, false)))
}; };
if(Device.RuntimePlatform == Device.iOS) if(Device.RuntimePlatform == Device.iOS)
@ -70,7 +71,7 @@ namespace Bit.App.Pages
FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Button)), FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Button)),
CancelButtonColor = Color.FromHex("3c8dbc") CancelButtonColor = Color.FromHex("3c8dbc")
}; };
// Bug with searchbar on android 7, ref https://bugzilla.xamarin.com/show_bug.cgi?id=43975 // Bug with search bar on android 7, ref https://bugzilla.xamarin.com/show_bug.cgi?id=43975
if(Device.RuntimePlatform == Device.Android && _deviceInfoService.Version >= 24) if(Device.RuntimePlatform == Device.Android && _deviceInfoService.Version >= 24)
{ {
Search.HeightRequest = 50; Search.HeightRequest = 50;
@ -204,7 +205,7 @@ namespace Bit.App.Pages
var ciphers = await _cipherService.GetAllAsync(); var ciphers = await _cipherService.GetAllAsync();
Ciphers = ciphers Ciphers = ciphers
.Select(s => new VaultListPageModel.Cipher(s, _appSettingsService)) .Select(s => new Cipher(s, _appSettingsService))
.OrderBy(s => .OrderBy(s =>
{ {
// Sort numbers and letters before special characters // Sort numbers and letters before special characters
@ -225,11 +226,10 @@ namespace Bit.App.Pages
return cts; return cts;
} }
private void LoadLetters(VaultListPageModel.Cipher[] ciphers, CancellationToken ct) private void LoadLetters(Cipher[] ciphers, CancellationToken ct)
{ {
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
var letterGroups = ciphers.GroupBy(c => c.NameGroup) var letterGroups = ciphers.GroupBy(c => c.NameGroup).Select(g => new Section<Cipher>(g.ToList(), g.Key));
.Select(g => new VaultListPageModel.NameGroup(g.Key, g.ToList()));
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
Device.BeginInvokeOnMainThread(() => Device.BeginInvokeOnMainThread(() =>
{ {
@ -240,7 +240,7 @@ namespace Bit.App.Pages
private async void CipherSelected(object sender, SelectedItemChangedEventArgs e) private async void CipherSelected(object sender, SelectedItemChangedEventArgs e)
{ {
var cipher = e.SelectedItem as VaultListPageModel.Cipher; var cipher = e.SelectedItem as Cipher;
if(cipher == null) if(cipher == null)
{ {
return; return;