1
0
mirror of https://github.com/bitwarden/mobile.git synced 2024-11-25 12:05:59 +01:00

Fix iOS 15.4 crash from empty list to adding an item by awaiting after every header add; also added that on Settings just in case there is another crash scenario. (#1850)

This commit is contained in:
Federico Maccaroni 2022-03-17 17:33:22 -03:00 committed by GitHub
parent c1748acf39
commit 22b00bcb33
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 255 additions and 104 deletions

View File

@ -0,0 +1,6 @@
namespace Bit.App.Pages
{
public interface ISendGroupingsPageListItem
{
}
}

View File

@ -73,7 +73,29 @@
</controls:ExtendedStackLayout> </controls:ExtendedStackLayout>
</DataTemplate> </DataTemplate>
<DataTemplate
x:Key="headerTemplate"
x:DataType="pages:SendGroupingsPageHeaderListItem">
<StackLayout
Spacing="0" Padding="0" VerticalOptions="FillAndExpand"
StyleClass="list-row-header-container, list-row-header-container-platform">
<BoxView
StyleClass="list-section-separator-top, list-section-separator-top-platform" />
<StackLayout StyleClass="list-row-header, list-row-header-platform">
<Label
Text="{Binding Title}"
StyleClass="list-header, list-header-platform" />
<Label
Text="{Binding ItemCount}"
StyleClass="list-header-sub" />
</StackLayout>
<BoxView
StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
</StackLayout>
</DataTemplate>
<pages:SendGroupingsPageListItemSelector x:Key="sendListItemDataTemplateSelector" <pages:SendGroupingsPageListItemSelector x:Key="sendListItemDataTemplateSelector"
HeaderTemplate="{StaticResource headerTemplate}"
SendTemplate="{StaticResource sendTemplate}" SendTemplate="{StaticResource sendTemplate}"
GroupTemplate="{StaticResource sendGroupTemplate}" /> GroupTemplate="{StaticResource sendGroupTemplate}" />
@ -114,32 +136,9 @@
ItemsSource="{Binding GroupedSends}" ItemsSource="{Binding GroupedSends}"
VerticalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
ItemTemplate="{StaticResource sendListItemDataTemplateSelector}" ItemTemplate="{StaticResource sendListItemDataTemplateSelector}"
IsGrouped="True"
SelectionMode="Single" SelectionMode="Single"
SelectionChanged="RowSelected" SelectionChanged="RowSelected"
StyleClass="list, list-platform"> StyleClass="list, list-platform" />
<CollectionView.GroupHeaderTemplate>
<DataTemplate x:DataType="pages:SendGroupingsPageListGroup">
<StackLayout
Spacing="0" Padding="0" VerticalOptions="FillAndExpand"
StyleClass="list-row-header-container, list-row-header-container-platform">
<BoxView
StyleClass="list-section-separator-top, list-section-separator-top-platform" />
<StackLayout StyleClass="list-row-header, list-row-header-platform">
<Label
Text="{Binding Name}"
StyleClass="list-header, list-header-platform" />
<Label
Text="{Binding ItemCount}"
StyleClass="list-header-sub" />
</StackLayout>
<BoxView
StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
</StackLayout>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
</controls:ExtendedCollectionView>
</RefreshView> </RefreshView>
</StackLayout> </StackLayout>
</ResourceDictionary> </ResourceDictionary>

View File

@ -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; }
}
}

View File

@ -5,7 +5,7 @@ using Bit.Core.Models.View;
namespace Bit.App.Pages namespace Bit.App.Pages
{ {
public class SendGroupingsPageListItem public class SendGroupingsPageListItem : ISendGroupingsPageListItem
{ {
private string _icon; private string _icon;
private string _name; private string _name;

View File

@ -4,11 +4,17 @@ namespace Bit.App.Pages
{ {
public class SendGroupingsPageListItemSelector : DataTemplateSelector public class SendGroupingsPageListItemSelector : DataTemplateSelector
{ {
public DataTemplate HeaderTemplate { get; set; }
public DataTemplate SendTemplate { get; set; } public DataTemplate SendTemplate { get; set; }
public DataTemplate GroupTemplate { get; set; } public DataTemplate GroupTemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container) protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{ {
if (item is SendGroupingsPageHeaderListItem)
{
return HeaderTemplate;
}
if (item is SendGroupingsPageListItem listItem) if (item is SendGroupingsPageListItem listItem)
{ {
return listItem.Send != null ? SendTemplate : GroupTemplate; return listItem.Send != null ? SendTemplate : GroupTemplate;

View File

@ -10,6 +10,7 @@ using Bit.Core.Abstractions;
using Bit.Core.Enums; using Bit.Core.Enums;
using Bit.Core.Models.View; using Bit.Core.Models.View;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Xamarin.CommunityToolkit.ObjectModel;
using Xamarin.Essentials; using Xamarin.Essentials;
using Xamarin.Forms; using Xamarin.Forms;
using DeviceType = Bit.Core.Enums.DeviceType; using DeviceType = Bit.Core.Enums.DeviceType;
@ -48,7 +49,7 @@ namespace Bit.App.Pages
Loading = true; Loading = true;
PageTitle = AppResources.Send; PageTitle = AppResources.Send;
GroupedSends = new ExtendedObservableCollection<SendGroupingsPageListGroup>(); GroupedSends = new ObservableRangeCollection<ISendGroupingsPageListItem>();
RefreshCommand = new Command(async () => RefreshCommand = new Command(async () =>
{ {
Refreshing = true; Refreshing = true;
@ -103,7 +104,7 @@ namespace Bit.App.Pages
get => _showList; get => _showList;
set => SetProperty(ref _showList, value); set => SetProperty(ref _showList, value);
} }
public ExtendedObservableCollection<SendGroupingsPageListGroup> GroupedSends { get; set; } public ObservableRangeCollection<ISendGroupingsPageListItem> GroupedSends { get; set; }
public Command RefreshCommand { get; set; } public Command RefreshCommand { get; set; }
public Command<SendView> SendOptionsCommand { get; set; } public Command<SendView> SendOptionsCommand { get; set; }
public bool LoadedOnce { get; set; } public bool LoadedOnce { get; set; }
@ -175,7 +176,33 @@ namespace Bit.App.Pages
MainPage ? AppResources.AllSends : AppResources.Sends, sendsListItems.Count, MainPage ? AppResources.AllSends : AppResources.Sends, sendsListItems.Count,
uppercaseGroupNames, !MainPage)); uppercaseGroupNames, !MainPage));
} }
GroupedSends.ResetWithRange(groupedSends);
// TODO: refactor this
if (Device.RuntimePlatform == Device.Android)
{
var items = new List<ISendGroupingsPageListItem>();
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 finally
{ {

View File

@ -513,13 +513,36 @@ namespace Bit.App.Pages
new SettingsPageListGroup(toolsItems, AppResources.Tools, doUpper), new SettingsPageListGroup(toolsItems, AppResources.Tools, doUpper),
new SettingsPageListGroup(otherItems, AppResources.Other, doUpper) new SettingsPageListGroup(otherItems, AppResources.Other, doUpper)
}; };
var settingsItems = new List<ISettingsPageListItem>();
foreach (var itemGroup in settingsListGroupItems) // TODO: refactor this
if (Device.RuntimePlatform == Device.Android)
{ {
settingsItems.Add(new SettingsPageHeaderListItem(itemGroup.Name)); var items = new List<ISettingsPageListItem>();
settingsItems.AddRange(itemGroup); 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() private bool IncludeLinksWithSubscriptionInfo()

View File

@ -30,7 +30,27 @@
WebsiteIconsEnabled="{Binding BindingContext.WebsiteIconsEnabled, Source={x:Reference _page}}" /> WebsiteIconsEnabled="{Binding BindingContext.WebsiteIconsEnabled, Source={x:Reference _page}}" />
</DataTemplate> </DataTemplate>
<DataTemplate
x:Key="headerTemplate"
x:DataType="pages:GroupingsPageHeaderListItem">
<StackLayout
Spacing="0" Padding="0" VerticalOptions="FillAndExpand"
StyleClass="list-row-header-container, list-row-header-container-platform">
<BoxView
StyleClass="list-section-separator-top, list-section-separator-top-platform" />
<StackLayout StyleClass="list-row-header, list-row-header-platform">
<Label
Text="{Binding Title}"
StyleClass="list-header, list-header-platform" />
<Label
Text="{Binding ItemCount}"
StyleClass="list-header-sub" />
</StackLayout>
</StackLayout>
</DataTemplate>
<pages:GroupingsPageListItemSelector x:Key="listItemDataTemplateSelector" <pages:GroupingsPageListItemSelector x:Key="listItemDataTemplateSelector"
HeaderTemplate="{StaticResource headerTemplate}"
CipherTemplate="{StaticResource cipherTemplate}" /> CipherTemplate="{StaticResource cipherTemplate}" />
<StackLayout x:Key="mainLayout" x:Name="_mainLayout"> <StackLayout x:Key="mainLayout" x:Name="_mainLayout">
@ -52,30 +72,9 @@
ItemsSource="{Binding GroupedItems}" ItemsSource="{Binding GroupedItems}"
VerticalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
ItemTemplate="{StaticResource listItemDataTemplateSelector}" ItemTemplate="{StaticResource listItemDataTemplateSelector}"
IsGrouped="True"
SelectionMode="Single" SelectionMode="Single"
SelectionChanged="RowSelected" SelectionChanged="RowSelected"
StyleClass="list, list-platform"> StyleClass="list, list-platform" />
<CollectionView.GroupHeaderTemplate>
<DataTemplate x:DataType="pages:GroupingsPageListGroup">
<StackLayout
Spacing="0" Padding="0" VerticalOptions="FillAndExpand"
StyleClass="list-row-header-container, list-row-header-container-platform">
<BoxView
StyleClass="list-section-separator-top, list-section-separator-top-platform" />
<StackLayout StyleClass="list-row-header, list-row-header-platform">
<Label
Text="{Binding Name}"
StyleClass="list-header, list-header-platform" />
<Label
Text="{Binding ItemCount}"
StyleClass="list-header-sub" />
</StackLayout>
</StackLayout>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
</controls:ExtendedCollectionView>
</StackLayout> </StackLayout>
</ResourceDictionary> </ResourceDictionary>
</ContentPage.Resources> </ContentPage.Resources>

View File

@ -11,6 +11,7 @@ using Bit.Core.Utilities;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Xamarin.CommunityToolkit.ObjectModel;
using Xamarin.Forms; using Xamarin.Forms;
namespace Bit.App.Pages namespace Bit.App.Pages
@ -36,14 +37,14 @@ namespace Bit.App.Pages
_stateService = ServiceContainer.Resolve<IStateService>("stateService"); _stateService = ServiceContainer.Resolve<IStateService>("stateService");
_passwordRepromptService = ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService"); _passwordRepromptService = ServiceContainer.Resolve<IPasswordRepromptService>("passwordRepromptService");
GroupedItems = new ExtendedObservableCollection<GroupingsPageListGroup>(); GroupedItems = new ObservableRangeCollection<IGroupingsPageListItem>();
CipherOptionsCommand = new Command<CipherView>(CipherOptionsAsync); CipherOptionsCommand = new Command<CipherView>(CipherOptionsAsync);
} }
public string Name { get; set; } public string Name { get; set; }
public string Uri { get; set; } public string Uri { get; set; }
public Command CipherOptionsCommand { get; set; } public Command CipherOptionsCommand { get; set; }
public ExtendedObservableCollection<GroupingsPageListGroup> GroupedItems { get; set; } public ObservableRangeCollection<IGroupingsPageListItem> GroupedItems { get; set; }
public bool ShowList public bool ShowList
{ {
@ -105,7 +106,33 @@ namespace Bit.App.Pages
new GroupingsPageListGroup(fuzzy, AppResources.PossibleMatchingItems, fuzzy.Count, false, new GroupingsPageListGroup(fuzzy, AppResources.PossibleMatchingItems, fuzzy.Count, false,
!hasMatching)); !hasMatching));
} }
GroupedItems.ResetWithRange(groupedItems);
// TODO: refactor this
if (Device.RuntimePlatform == Device.Android)
{
var items = new List<IGroupingsPageListItem>();
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(); ShowList = groupedItems.Any();
} }

View File

@ -55,30 +55,53 @@
<DataTemplate x:Key="groupTemplate" <DataTemplate x:Key="groupTemplate"
x:DataType="pages:GroupingsPageListItem"> x:DataType="pages:GroupingsPageListItem">
<controls:ExtendedStackLayout Orientation="Horizontal" <controls:ExtendedStackLayout Orientation="Horizontal"
StyleClass="list-row, list-row-platform"> StyleClass="list-row, list-row-platform">
<controls:IconLabel Text="{Binding Icon, Mode=OneWay}" <controls:IconLabel Text="{Binding Icon, Mode=OneWay}"
HorizontalOptions="Start" HorizontalOptions="Start"
VerticalOptions="Center" VerticalOptions="Center"
StyleClass="list-icon, list-icon-platform" StyleClass="list-icon, list-icon-platform"
ShouldUpdateFontSizeDynamicallyForAccesibility="True"> ShouldUpdateFontSizeDynamicallyForAccesibility="True">
<controls:IconLabel.Effects> <controls:IconLabel.Effects>
<effects:FixedSizeEffect /> <effects:FixedSizeEffect />
</controls:IconLabel.Effects> </controls:IconLabel.Effects>
</controls:IconLabel> </controls:IconLabel>
<Label Text="{Binding Name, Mode=OneWay}" <Label Text="{Binding Name, Mode=OneWay}"
LineBreakMode="TailTruncation" LineBreakMode="TailTruncation"
HorizontalOptions="FillAndExpand" HorizontalOptions="FillAndExpand"
VerticalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"
StyleClass="list-title"/> StyleClass="list-title"/>
<Label Text="{Binding ItemCount, Mode=OneWay}" <Label Text="{Binding ItemCount, Mode=OneWay}"
HorizontalOptions="End" HorizontalOptions="End"
VerticalOptions="CenterAndExpand" VerticalOptions="CenterAndExpand"
HorizontalTextAlignment="End" HorizontalTextAlignment="End"
StyleClass="list-sub"/> StyleClass="list-sub"/>
</controls:ExtendedStackLayout> </controls:ExtendedStackLayout>
</DataTemplate> </DataTemplate>
<DataTemplate
x:Key="headerTemplate"
x:DataType="pages:GroupingsPageHeaderListItem">
<StackLayout
Spacing="0"
Padding="0"
VerticalOptions="FillAndExpand"
StyleClass="list-row-header-container, list-row-header-container-platform">
<BoxView
StyleClass="list-section-separator-top, list-section-separator-top-platform" />
<StackLayout StyleClass="list-row-header, list-row-header-platform">
<Label
Text="{Binding Title}"
StyleClass="list-header, list-header-platform" />
<Label
Text="{Binding ItemCount}"
StyleClass="list-header-sub" />
</StackLayout>
<BoxView StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
</StackLayout>
</DataTemplate>
<pages:GroupingsPageListItemSelector x:Key="listItemDataTemplateSelector" <pages:GroupingsPageListItemSelector x:Key="listItemDataTemplateSelector"
HeaderTemplate="{StaticResource headerTemplate}"
CipherTemplate="{StaticResource cipherTemplate}" CipherTemplate="{StaticResource cipherTemplate}"
GroupTemplate="{StaticResource groupTemplate}" /> GroupTemplate="{StaticResource groupTemplate}" />
@ -105,31 +128,9 @@
ItemsSource="{Binding GroupedItems}" ItemsSource="{Binding GroupedItems}"
VerticalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
ItemTemplate="{StaticResource listItemDataTemplateSelector}" ItemTemplate="{StaticResource listItemDataTemplateSelector}"
IsGrouped="True"
SelectionMode="Single" SelectionMode="Single"
SelectionChanged="RowSelected" SelectionChanged="RowSelected"
StyleClass="list, list-platform"> StyleClass="list, list-platform" />
<CollectionView.GroupHeaderTemplate>
<DataTemplate x:DataType="pages:GroupingsPageListGroup">
<StackLayout
Spacing="0" Padding="0" VerticalOptions="FillAndExpand"
StyleClass="list-row-header-container, list-row-header-container-platform">
<BoxView
StyleClass="list-section-separator-top, list-section-separator-top-platform" />
<StackLayout StyleClass="list-row-header, list-row-header-platform">
<Label
Text="{Binding Name}"
StyleClass="list-header, list-header-platform" />
<Label
Text="{Binding ItemCount}"
StyleClass="list-header-sub" />
</StackLayout>
<BoxView StyleClass="list-section-separator-bottom, list-section-separator-bottom-platform" />
</StackLayout>
</DataTemplate>
</CollectionView.GroupHeaderTemplate>
</controls:ExtendedCollectionView>
</RefreshView> </RefreshView>
</StackLayout> </StackLayout>
</ResourceDictionary> </ResourceDictionary>

View File

@ -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; }
}
}

View File

@ -5,7 +5,7 @@ using Bit.Core.Models.View;
namespace Bit.App.Pages namespace Bit.App.Pages
{ {
public class GroupingsPageListItem public class GroupingsPageListItem : IGroupingsPageListItem
{ {
private string _icon; private string _icon;
private string _name; private string _name;

View File

@ -4,11 +4,17 @@ namespace Bit.App.Pages
{ {
public class GroupingsPageListItemSelector : DataTemplateSelector public class GroupingsPageListItemSelector : DataTemplateSelector
{ {
public DataTemplate HeaderTemplate { get; set; }
public DataTemplate CipherTemplate { get; set; } public DataTemplate CipherTemplate { get; set; }
public DataTemplate GroupTemplate { get; set; } public DataTemplate GroupTemplate { get; set; }
protected override DataTemplate OnSelectTemplate(object item, BindableObject container) protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
{ {
if (item is GroupingsPageHeaderListItem)
{
return HeaderTemplate;
}
if (item is GroupingsPageListItem listItem) if (item is GroupingsPageListItem listItem)
{ {
return listItem.Cipher != null ? CipherTemplate : GroupTemplate; return listItem.Cipher != null ? CipherTemplate : GroupTemplate;

View File

@ -11,6 +11,7 @@ using Bit.Core.Enums;
using Bit.Core.Models.Domain; using Bit.Core.Models.Domain;
using Bit.Core.Models.View; using Bit.Core.Models.View;
using Bit.Core.Utilities; using Bit.Core.Utilities;
using Xamarin.CommunityToolkit.ObjectModel;
using Xamarin.Forms; using Xamarin.Forms;
namespace Bit.App.Pages namespace Bit.App.Pages
@ -63,7 +64,7 @@ namespace Bit.App.Pages
Loading = true; Loading = true;
PageTitle = AppResources.MyVault; PageTitle = AppResources.MyVault;
GroupedItems = new ExtendedObservableCollection<GroupingsPageListGroup>(); GroupedItems = new ObservableRangeCollection<IGroupingsPageListItem>();
RefreshCommand = new Command(async () => RefreshCommand = new Command(async () =>
{ {
Refreshing = true; Refreshing = true;
@ -144,7 +145,7 @@ namespace Bit.App.Pages
public AccountSwitchingOverlayViewModel AccountSwitchingOverlayViewModel { get; } public AccountSwitchingOverlayViewModel AccountSwitchingOverlayViewModel { get; }
public ExtendedObservableCollection<GroupingsPageListGroup> GroupedItems { get; set; } public ObservableRangeCollection<IGroupingsPageListItem> GroupedItems { get; set; }
public Command RefreshCommand { get; set; } public Command RefreshCommand { get; set; }
public Command<CipherView> CipherOptionsCommand { get; set; } public Command<CipherView> CipherOptionsCommand { get; set; }
public bool LoadedOnce { get; set; } public bool LoadedOnce { get; set; }
@ -280,7 +281,33 @@ namespace Bit.App.Pages
} }
}, AppResources.Trash, _deletedCount, uppercaseGroupNames, false)); }, AppResources.Trash, _deletedCount, uppercaseGroupNames, false));
} }
GroupedItems.ResetWithRange(groupedItems);
// TODO: refactor this
if (Device.RuntimePlatform == Device.Android)
{
var items = new List<IGroupingsPageListItem>();
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 finally
{ {

View File

@ -0,0 +1,6 @@
namespace Bit.App.Pages
{
public interface IGroupingsPageListItem
{
}
}

View File

@ -228,11 +228,7 @@ namespace Bit.iOS
public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options) public override bool OpenUrl(UIApplication app, NSUrl url, NSDictionary options)
{ {
if (Xamarin.Essentials.Platform.OpenUrl(app, url, options)) return Xamarin.Essentials.Platform.OpenUrl(app, url, options);
{
return true;
}
return base.OpenUrl(app, url, options);
} }
public override bool ContinueUserActivity(UIApplication application, NSUserActivity userActivity, public override bool ContinueUserActivity(UIApplication application, NSUserActivity userActivity,