handle conditions when no data

This commit is contained in:
Kyle Spearrin 2017-11-27 15:05:12 -05:00
parent b07dc8443e
commit 92b7b1d603
4 changed files with 86 additions and 24 deletions

View file

@ -56,11 +56,12 @@ namespace Bit.App.Pages
Init(); Init();
} }
public ExtendedObservableCollection<Section<Cipher>> PresentationLetters { get; private set; } public ExtendedObservableCollection<Section<Cipher>> PresentationSections { get; private set; }
= new ExtendedObservableCollection<Section<Cipher>>(); = new ExtendedObservableCollection<Section<Cipher>>();
public Cipher[] Ciphers { get; set; } = new 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 NoDataStackLayout { get; set; }
public StackLayout ResultsStackLayout { get; set; } public StackLayout ResultsStackLayout { get; set; }
private AddCipherToolBarItem AddCipherItem { get; set; } private AddCipherToolBarItem AddCipherItem { get; set; }
@ -75,7 +76,7 @@ namespace Bit.App.Pages
ListView = new ListView(ListViewCachingStrategy.RecycleElement) ListView = new ListView(ListViewCachingStrategy.RecycleElement)
{ {
IsGroupingEnabled = true, IsGroupingEnabled = true,
ItemsSource = PresentationLetters, ItemsSource = PresentationSections,
HasUnevenRows = true, HasUnevenRows = true,
GroupHeaderTemplate = new DataTemplate(() => new SectionHeaderViewCell(nameof(Section<Cipher>.Name), GroupHeaderTemplate = new DataTemplate(() => new SectionHeaderViewCell(nameof(Section<Cipher>.Name),
nameof(Section<Cipher>.Count))), nameof(Section<Cipher>.Count))),
@ -101,6 +102,41 @@ namespace Bit.App.Pages
Search.HeightRequest = 50; Search.HeightRequest = 50;
} }
var noDataLabel = new Label
{
Text = _favorites ? AppResources.NoFavorites : AppResources.NoItems,
HorizontalTextAlignment = TextAlignment.Center,
FontSize = Device.GetNamedSize(NamedSize.Small, typeof(Label)),
Style = (Style)Application.Current.Resources["text-muted"]
};
if(_folder || !string.IsNullOrWhiteSpace(_folderId))
{
noDataLabel.Text = AppResources.NoItemsFolder;
}
else if(!string.IsNullOrWhiteSpace(_collectionId))
{
noDataLabel.Text = AppResources.NoItemsCollection;
}
NoDataStackLayout = new StackLayout
{
Children = { noDataLabel },
VerticalOptions = LayoutOptions.CenterAndExpand,
Padding = new Thickness(20, 0),
Spacing = 20
};
if(string.IsNullOrWhiteSpace(_collectionId) && !_favorites)
{
NoDataStackLayout.Children.Add(new ExtendedButton
{
Text = AppResources.AddAnItem,
Command = new Command(() => Helpers.AddCipher(this, _folderId)),
Style = (Style)Application.Current.Resources["btn-primaryAccent"]
});
}
ResultsStackLayout = new StackLayout ResultsStackLayout = new StackLayout
{ {
Children = { Search, ListView }, Children = { Search, ListView },
@ -182,7 +218,7 @@ namespace Bit.App.Pages
if(string.IsNullOrWhiteSpace(searchFilter)) if(string.IsNullOrWhiteSpace(searchFilter))
{ {
LoadLetters(Ciphers, ct); LoadSections(Ciphers, ct);
} }
else else
{ {
@ -194,7 +230,7 @@ namespace Bit.App.Pages
.ToArray(); .ToArray();
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
LoadLetters(filteredCiphers, ct); LoadSections(filteredCiphers, ct);
} }
} }
@ -248,7 +284,7 @@ namespace Bit.App.Pages
private CancellationTokenSource FetchAndLoadVault() private CancellationTokenSource FetchAndLoadVault()
{ {
var cts = new CancellationTokenSource(); var cts = new CancellationTokenSource();
if(PresentationLetters.Count > 0 && _syncService.SyncInProgress) if(PresentationSections.Count > 0 && _syncService.SyncInProgress)
{ {
return cts; return cts;
} }
@ -281,7 +317,7 @@ namespace Bit.App.Pages
{ {
// Sort numbers and letters before special characters // Sort numbers and letters before special characters
return !string.IsNullOrWhiteSpace(s.Name) && s.Name.Length > 0 && return !string.IsNullOrWhiteSpace(s.Name) && s.Name.Length > 0 &&
Char.IsLetterOrDigit(s.Name[0]) ? 0 : 1; Char.IsDigit(s.Name[0]) ? 0 : Char.IsLetter(s.Name[0]) ? 1 : 2;
}) })
.ThenBy(s => s.Name) .ThenBy(s => s.Name)
.ThenBy(s => s.Subtitle) .ThenBy(s => s.Subtitle)
@ -297,15 +333,22 @@ namespace Bit.App.Pages
return cts; return cts;
} }
private void LoadLetters(Cipher[] ciphers, CancellationToken ct) private void LoadSections(Cipher[] ciphers, CancellationToken ct)
{ {
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
var letterGroups = ciphers.GroupBy(c => c.NameGroup).Select(g => new Section<Cipher>(g.ToList(), g.Key)); var sections = ciphers.GroupBy(c => c.NameGroup).Select(g => new Section<Cipher>(g.ToList(), g.Key));
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
Device.BeginInvokeOnMainThread(() => Device.BeginInvokeOnMainThread(() =>
{ {
PresentationLetters.ResetWithRange(letterGroups); PresentationSections.ResetWithRange(sections);
Content = ResultsStackLayout; if(PresentationSections.Count > 0 || !string.IsNullOrWhiteSpace(Search.Text))
{
Content = ResultsStackLayout;
}
else
{
Content = NoDataStackLayout;
}
}); });
} }

View file

@ -90,14 +90,6 @@ namespace Bit.App.Pages
Style = (Style)Application.Current.Resources["text-muted"] Style = (Style)Application.Current.Resources["text-muted"]
}; };
NoDataStackLayout = new StackLayout
{
Children = { noDataLabel },
VerticalOptions = LayoutOptions.CenterAndExpand,
Padding = new Thickness(20, 0),
Spacing = 20
};
var addCipherButton = new ExtendedButton var addCipherButton = new ExtendedButton
{ {
Text = AppResources.AddAnItem, Text = AppResources.AddAnItem,
@ -105,7 +97,13 @@ namespace Bit.App.Pages
Style = (Style)Application.Current.Resources["btn-primaryAccent"] Style = (Style)Application.Current.Resources["btn-primaryAccent"]
}; };
NoDataStackLayout.Children.Add(addCipherButton); NoDataStackLayout = new StackLayout
{
Children = { noDataLabel, addCipherButton },
VerticalOptions = LayoutOptions.CenterAndExpand,
Padding = new Thickness(20, 0),
Spacing = 20
};
LoadingIndicator = new ActivityIndicator LoadingIndicator = new ActivityIndicator
{ {
@ -225,12 +223,9 @@ namespace Bit.App.Pages
Device.BeginInvokeOnMainThread(() => Device.BeginInvokeOnMainThread(() =>
{ {
if(sections.Any()) PresentationSections.ResetWithRange(sections);
{
PresentationSections.ResetWithRange(sections);
}
if(PresentationSections.Count > 0) if(ciphers.Any() || folders.Any())
{ {
Content = ListView; Content = ListView;
} }

View file

@ -2113,6 +2113,24 @@ namespace Bit.App.Resources {
} }
} }
/// <summary>
/// Looks up a localized string similar to There are no items in this collection..
/// </summary>
public static string NoItemsCollection {
get {
return ResourceManager.GetString("NoItemsCollection", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to There are no items in this folder..
/// </summary>
public static string NoItemsFolder {
get {
return ResourceManager.GetString("NoItemsFolder", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to There are no items in your vault for {0}.. /// Looks up a localized string similar to There are no items in your vault for {0}..
/// </summary> /// </summary>

View file

@ -1203,4 +1203,10 @@
<data name="DefaultPageVaultDescription" xml:space="preserve"> <data name="DefaultPageVaultDescription" xml:space="preserve">
<value>Default to the "My Vault" page instead of "Favorites" whenever I open the app.</value> <value>Default to the "My Vault" page instead of "Favorites" whenever I open the app.</value>
</data> </data>
<data name="NoItemsCollection" xml:space="preserve">
<value>There are no items in this collection.</value>
</data>
<data name="NoItemsFolder" xml:space="preserve">
<value>There are no items in this folder.</value>
</data>
</root> </root>