diff --git a/src/App/Pages/Send/SendGroupingsPage/ISendGroupingsPageListItem.cs b/src/App/Pages/Send/SendGroupingsPage/ISendGroupingsPageListItem.cs
new file mode 100644
index 000000000..6b8b84801
--- /dev/null
+++ b/src/App/Pages/Send/SendGroupingsPage/ISendGroupingsPageListItem.cs
@@ -0,0 +1,6 @@
+namespace Bit.App.Pages
+{
+ public interface ISendGroupingsPageListItem
+ {
+ }
+}
diff --git a/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPage.xaml b/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPage.xaml
index d4703ae76..532be317a 100644
--- a/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPage.xaml
+++ b/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPage.xaml
@@ -72,7 +72,29 @@
+
+
+
+
+
+
+
+
+
+
+
@@ -113,32 +135,9 @@
ItemsSource="{Binding GroupedSends}"
VerticalOptions="FillAndExpand"
ItemTemplate="{StaticResource sendListItemDataTemplateSelector}"
- IsGrouped="True"
SelectionMode="Single"
SelectionChanged="RowSelected"
- StyleClass="list, list-platform">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ StyleClass="list, list-platform" />
diff --git a/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPageHeaderListItem.cs b/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPageHeaderListItem.cs
new file mode 100644
index 000000000..c8c7943be
--- /dev/null
+++ b/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPageHeaderListItem.cs
@@ -0,0 +1,14 @@
+namespace Bit.App.Pages
+{
+ public class SendGroupingsPageHeaderListItem : ISendGroupingsPageListItem
+ {
+ public SendGroupingsPageHeaderListItem(string title, string itemCount)
+ {
+ Title = title;
+ ItemCount = itemCount;
+ }
+
+ public string Title { get; }
+ public string ItemCount { get; }
+ }
+}
diff --git a/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPageListItem.cs b/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPageListItem.cs
index 00d1bccbd..a89ebf18d 100644
--- a/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPageListItem.cs
+++ b/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPageListItem.cs
@@ -5,7 +5,7 @@ using Bit.Core.Models.View;
namespace Bit.App.Pages
{
- public class SendGroupingsPageListItem
+ public class SendGroupingsPageListItem : ISendGroupingsPageListItem
{
private string _icon;
private string _name;
diff --git a/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPageListItemSelector.cs b/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPageListItemSelector.cs
index 885bc0fb5..3eb8a6019 100644
--- a/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPageListItemSelector.cs
+++ b/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPageListItemSelector.cs
@@ -4,11 +4,17 @@ namespace Bit.App.Pages
{
public class SendGroupingsPageListItemSelector : DataTemplateSelector
{
+ public DataTemplate HeaderTemplate { get; set; }
public DataTemplate SendTemplate { get; set; }
public DataTemplate GroupTemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
+ if (item is SendGroupingsPageHeaderListItem)
+ {
+ return HeaderTemplate;
+ }
+
if (item is SendGroupingsPageListItem listItem)
{
return listItem.Send != null ? SendTemplate : GroupTemplate;
diff --git a/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPageViewModel.cs b/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPageViewModel.cs
index b524aac91..fe54a979d 100644
--- a/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPageViewModel.cs
+++ b/src/App/Pages/Send/SendGroupingsPage/SendGroupingsPageViewModel.cs
@@ -10,6 +10,7 @@ using Bit.Core.Abstractions;
using Bit.Core.Enums;
using Bit.Core.Models.View;
using Bit.Core.Utilities;
+using Xamarin.CommunityToolkit.ObjectModel;
using Xamarin.Essentials;
using Xamarin.Forms;
using DeviceType = Bit.Core.Enums.DeviceType;
@@ -50,7 +51,7 @@ namespace Bit.App.Pages
Loading = true;
PageTitle = AppResources.Send;
- GroupedSends = new ExtendedObservableCollection();
+ GroupedSends = new ObservableRangeCollection();
RefreshCommand = new Command(async () =>
{
Refreshing = true;
@@ -105,7 +106,7 @@ namespace Bit.App.Pages
get => _showList;
set => SetProperty(ref _showList, value);
}
- public ExtendedObservableCollection GroupedSends { get; set; }
+ public ObservableRangeCollection GroupedSends { get; set; }
public Command RefreshCommand { get; set; }
public Command SendOptionsCommand { get; set; }
public bool LoadedOnce { get; set; }
@@ -177,7 +178,33 @@ namespace Bit.App.Pages
MainPage ? AppResources.AllSends : AppResources.Sends, sendsListItems.Count,
uppercaseGroupNames, !MainPage));
}
- GroupedSends.ResetWithRange(groupedSends);
+
+ // TODO: refactor this
+ if (Device.RuntimePlatform == Device.Android)
+ {
+ var items = new List();
+ foreach (var itemGroup in groupedSends)
+ {
+ items.Add(new SendGroupingsPageHeaderListItem(itemGroup.Name, itemGroup.ItemCount));
+ items.AddRange(itemGroup);
+ }
+
+ GroupedSends.ReplaceRange(items);
+ }
+ else
+ {
+ // HACK: This waitings are to avoid crash on iOS
+ GroupedSends.Clear();
+ await Task.Delay(60);
+
+ foreach (var itemGroup in groupedSends)
+ {
+ GroupedSends.Add(new SendGroupingsPageHeaderListItem(itemGroup.Name, itemGroup.ItemCount));
+ await Task.Delay(60);
+
+ GroupedSends.AddRange(itemGroup);
+ }
+ }
}
finally
{
diff --git a/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs b/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs
index e34521143..9092d6028 100644
--- a/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs
+++ b/src/App/Pages/Settings/SettingsPage/SettingsPageViewModel.cs
@@ -521,13 +521,36 @@ namespace Bit.App.Pages
new SettingsPageListGroup(toolsItems, AppResources.Tools, doUpper),
new SettingsPageListGroup(otherItems, AppResources.Other, doUpper)
};
- var settingsItems = new List();
- foreach (var itemGroup in settingsListGroupItems)
+
+ // TODO: refactor this
+ if (Device.RuntimePlatform == Device.Android)
{
- settingsItems.Add(new SettingsPageHeaderListItem(itemGroup.Name));
- settingsItems.AddRange(itemGroup);
+ var items = new List();
+ foreach (var itemGroup in settingsListGroupItems)
+ {
+ items.Add(new SettingsPageHeaderListItem(itemGroup.Name));
+ items.AddRange(itemGroup);
+ }
+
+ GroupedItems.ReplaceRange(items);
+ }
+ else
+ {
+ Device.InvokeOnMainThreadAsync(async () =>
+ {
+ // HACK: This waitings are to avoid crash on iOS
+ GroupedItems.Clear();
+ await Task.Delay(60);
+
+ foreach (var itemGroup in settingsListGroupItems)
+ {
+ GroupedItems.Add(new SettingsPageHeaderListItem(itemGroup.Name));
+ await Task.Delay(60);
+
+ GroupedItems.AddRange(itemGroup);
+ }
+ }).FireAndForget();
}
- GroupedItems.ReplaceRange(settingsItems);
}
private bool IncludeLinksWithSubscriptionInfo()
diff --git a/src/App/Pages/Vault/AutofillCiphersPage.xaml b/src/App/Pages/Vault/AutofillCiphersPage.xaml
index 8b9bdeff0..5bb8b4004 100644
--- a/src/App/Pages/Vault/AutofillCiphersPage.xaml
+++ b/src/App/Pages/Vault/AutofillCiphersPage.xaml
@@ -29,8 +29,28 @@
ButtonCommand="{Binding BindingContext.CipherOptionsCommand, Source={x:Reference _page}}"
WebsiteIconsEnabled="{Binding BindingContext.WebsiteIconsEnabled, Source={x:Reference _page}}" />
+
+
+
+
+
+
+
+
+
+
@@ -52,30 +72,9 @@
ItemsSource="{Binding GroupedItems}"
VerticalOptions="FillAndExpand"
ItemTemplate="{StaticResource listItemDataTemplateSelector}"
- IsGrouped="True"
SelectionMode="Single"
SelectionChanged="RowSelected"
- StyleClass="list, list-platform">
-
-
-
-
-
-
-
-
-
-
-
-
-
+ StyleClass="list, list-platform" />
diff --git a/src/App/Pages/Vault/AutofillCiphersPageViewModel.cs b/src/App/Pages/Vault/AutofillCiphersPageViewModel.cs
index 6deb7710a..7b181236c 100644
--- a/src/App/Pages/Vault/AutofillCiphersPageViewModel.cs
+++ b/src/App/Pages/Vault/AutofillCiphersPageViewModel.cs
@@ -13,6 +13,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+using Xamarin.CommunityToolkit.ObjectModel;
using Xamarin.Forms;
namespace Bit.App.Pages
@@ -38,14 +39,14 @@ namespace Bit.App.Pages
_stateService = ServiceContainer.Resolve("stateService");
_passwordRepromptService = ServiceContainer.Resolve("passwordRepromptService");
- GroupedItems = new ExtendedObservableCollection();
+ GroupedItems = new ObservableRangeCollection();
CipherOptionsCommand = new Command(CipherOptionsAsync);
}
public string Name { get; set; }
public string Uri { get; set; }
public Command CipherOptionsCommand { get; set; }
- public ExtendedObservableCollection GroupedItems { get; set; }
+ public ObservableRangeCollection GroupedItems { get; set; }
public bool ShowList
{
@@ -108,7 +109,33 @@ namespace Bit.App.Pages
new GroupingsPageListGroup(fuzzy, AppResources.PossibleMatchingItems, fuzzy.Count, false,
!hasMatching));
}
- GroupedItems.ResetWithRange(groupedItems);
+
+ // TODO: refactor this
+ if (Device.RuntimePlatform == Device.Android)
+ {
+ var items = new List();
+ foreach (var itemGroup in groupedItems)
+ {
+ items.Add(new GroupingsPageHeaderListItem(itemGroup.Name, itemGroup.ItemCount));
+ items.AddRange(itemGroup);
+ }
+
+ GroupedItems.ReplaceRange(items);
+ }
+ else
+ {
+ // HACK: This waitings are to avoid crash on iOS
+ GroupedItems.Clear();
+ await Task.Delay(60);
+
+ foreach (var itemGroup in groupedItems)
+ {
+ GroupedItems.Add(new GroupingsPageHeaderListItem(itemGroup.Name, itemGroup.ItemCount));
+ await Task.Delay(60);
+
+ GroupedItems.AddRange(itemGroup);
+ }
+ }
ShowList = groupedItems.Any();
}
diff --git a/src/App/Pages/Vault/GroupingsPage/GroupingsPage.xaml b/src/App/Pages/Vault/GroupingsPage/GroupingsPage.xaml
index 23fc29280..c8941f270 100644
--- a/src/App/Pages/Vault/GroupingsPage/GroupingsPage.xaml
+++ b/src/App/Pages/Vault/GroupingsPage/GroupingsPage.xaml
@@ -46,7 +46,7 @@
+ StyleClass="list-row, list-row-platform">
+ LineBreakMode="TailTruncation"
+ HorizontalOptions="FillAndExpand"
+ VerticalOptions="CenterAndExpand"
+ StyleClass="list-title"/>
+ HorizontalOptions="End"
+ VerticalOptions="CenterAndExpand"
+ HorizontalTextAlignment="End"
+ StyleClass="list-sub"/>
+
+
+
+
+
+
+
+
+
+
+
@@ -95,31 +118,9 @@
ItemsSource="{Binding GroupedItems}"
VerticalOptions="FillAndExpand"
ItemTemplate="{StaticResource listItemDataTemplateSelector}"
- IsGrouped="True"
SelectionMode="Single"
SelectionChanged="RowSelected"
- StyleClass="list, list-platform">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ StyleClass="list, list-platform" />
diff --git a/src/App/Pages/Vault/GroupingsPage/GroupingsPageHeaderListItem.cs b/src/App/Pages/Vault/GroupingsPage/GroupingsPageHeaderListItem.cs
new file mode 100644
index 000000000..e7912ebc2
--- /dev/null
+++ b/src/App/Pages/Vault/GroupingsPage/GroupingsPageHeaderListItem.cs
@@ -0,0 +1,14 @@
+namespace Bit.App.Pages
+{
+ public class GroupingsPageHeaderListItem : IGroupingsPageListItem
+ {
+ public GroupingsPageHeaderListItem(string title, string itemCount)
+ {
+ Title = title;
+ ItemCount = itemCount;
+ }
+
+ public string Title { get; }
+ public string ItemCount { get; set; }
+ }
+}
diff --git a/src/App/Pages/Vault/GroupingsPage/GroupingsPageListItem.cs b/src/App/Pages/Vault/GroupingsPage/GroupingsPageListItem.cs
index 11e15677a..34674d961 100644
--- a/src/App/Pages/Vault/GroupingsPage/GroupingsPageListItem.cs
+++ b/src/App/Pages/Vault/GroupingsPage/GroupingsPageListItem.cs
@@ -5,7 +5,7 @@ using Bit.Core.Models.View;
namespace Bit.App.Pages
{
- public class GroupingsPageListItem
+ public class GroupingsPageListItem : IGroupingsPageListItem
{
private string _icon;
private string _name;
diff --git a/src/App/Pages/Vault/GroupingsPage/GroupingsPageListItemSelector.cs b/src/App/Pages/Vault/GroupingsPage/GroupingsPageListItemSelector.cs
index 667aeee96..a2e2207b4 100644
--- a/src/App/Pages/Vault/GroupingsPage/GroupingsPageListItemSelector.cs
+++ b/src/App/Pages/Vault/GroupingsPage/GroupingsPageListItemSelector.cs
@@ -4,11 +4,17 @@ namespace Bit.App.Pages
{
public class GroupingsPageListItemSelector : DataTemplateSelector
{
+ public DataTemplate HeaderTemplate { get; set; }
public DataTemplate CipherTemplate { get; set; }
public DataTemplate GroupTemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{
+ if (item is GroupingsPageHeaderListItem)
+ {
+ return HeaderTemplate;
+ }
+
if (item is GroupingsPageListItem listItem)
{
return listItem.Cipher != null ? CipherTemplate : GroupTemplate;
diff --git a/src/App/Pages/Vault/GroupingsPage/GroupingsPageViewModel.cs b/src/App/Pages/Vault/GroupingsPage/GroupingsPageViewModel.cs
index 228c94fb6..4f6a32bdd 100644
--- a/src/App/Pages/Vault/GroupingsPage/GroupingsPageViewModel.cs
+++ b/src/App/Pages/Vault/GroupingsPage/GroupingsPageViewModel.cs
@@ -11,6 +11,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
+using Xamarin.CommunityToolkit.ObjectModel;
using Xamarin.Forms;
namespace Bit.App.Pages
@@ -65,7 +66,7 @@ namespace Bit.App.Pages
Loading = true;
PageTitle = AppResources.MyVault;
- GroupedItems = new ExtendedObservableCollection();
+ GroupedItems = new ObservableRangeCollection();
RefreshCommand = new Command(async () =>
{
Refreshing = true;
@@ -139,7 +140,7 @@ namespace Bit.App.Pages
get => _websiteIconsEnabled;
set => SetProperty(ref _websiteIconsEnabled, value);
}
- public ExtendedObservableCollection GroupedItems { get; set; }
+ public ObservableRangeCollection GroupedItems { get; set; }
public Command RefreshCommand { get; set; }
public Command CipherOptionsCommand { get; set; }
public bool LoadedOnce { get; set; }
@@ -271,12 +272,38 @@ namespace Bit.App.Pages
{
new GroupingsPageListItem()
{
- IsTrash = true,
+ IsTrash = true,
ItemCount = _deletedCount.ToString("N0")
}
}, AppResources.Trash, _deletedCount, uppercaseGroupNames, false));
}
- GroupedItems.ResetWithRange(groupedItems);
+
+ // TODO: refactor this
+ if (Device.RuntimePlatform == Device.Android)
+ {
+ var items = new List();
+ foreach (var itemGroup in groupedItems)
+ {
+ items.Add(new GroupingsPageHeaderListItem(itemGroup.Name, itemGroup.ItemCount));
+ items.AddRange(itemGroup);
+ }
+
+ GroupedItems.ReplaceRange(items);
+ }
+ else
+ {
+ // HACK: This waitings are to avoid crash on iOS
+ GroupedItems.Clear();
+ await Task.Delay(60);
+
+ foreach (var itemGroup in groupedItems)
+ {
+ GroupedItems.Add(new GroupingsPageHeaderListItem(itemGroup.Name, itemGroup.ItemCount));
+ await Task.Delay(60);
+
+ GroupedItems.AddRange(itemGroup);
+ }
+ }
}
finally
{
diff --git a/src/App/Pages/Vault/GroupingsPage/IGroupingsPageListItem.cs b/src/App/Pages/Vault/GroupingsPage/IGroupingsPageListItem.cs
new file mode 100644
index 000000000..56cb68d87
--- /dev/null
+++ b/src/App/Pages/Vault/GroupingsPage/IGroupingsPageListItem.cs
@@ -0,0 +1,6 @@
+namespace Bit.App.Pages
+{
+ public interface IGroupingsPageListItem
+ {
+ }
+}
diff --git a/src/iOS/AppDelegate.cs b/src/iOS/AppDelegate.cs
index 48c1bdd64..5ef4ade5f 100644
--- a/src/iOS/AppDelegate.cs
+++ b/src/iOS/AppDelegate.cs
@@ -234,11 +234,7 @@ namespace Bit.iOS
public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{
- if (Xamarin.Essentials.Platform.OpenUrl(app, url, options))
- {
- return true;
- }
- return base.OpenUrl(app, url, options);
+ return Xamarin.Essentials.Platform.OpenUrl(app, url, options);
}
public override bool ContinueUserActivity(UIApplication application, NSUserActivity userActivity,