diff --git a/.editorconfig b/.editorconfig index c71598a71..a596b627e 100644 --- a/.editorconfig +++ b/.editorconfig @@ -107,3 +107,9 @@ csharp_new_line_before_catch = true csharp_new_line_before_finally = true csharp_new_line_before_members_in_object_initializers = true csharp_new_line_before_members_in_anonymous_types = true + +# SA1011: Closing square brackets should be spaced correctly +dotnet_diagnostic.SA1011.severity = none + +# CS4014: Because this call is not awaited, execution of the current method continues before the call is completed +dotnet_diagnostic.CS4014.severity = error diff --git a/Directory.Build.props b/Directory.Build.props index 891e273b7..e7f7d987f 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,7 +2,9 @@ - 8.0 + 9.0 + enable + nullable diff --git a/Xamarin.CommunityToolkit.ruleset b/Xamarin.CommunityToolkit.ruleset index 0d4b31f43..047684820 100644 --- a/Xamarin.CommunityToolkit.ruleset +++ b/Xamarin.CommunityToolkit.ruleset @@ -15,7 +15,6 @@ - diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 10bb75744..a0ee31d07 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -7,10 +7,12 @@ variables: #MONO_VERSION: 6_4_0 #XCODE_VERSION: 11.4 NETCORE_VERSION: '5.0.x' - NETCORE_TEST_VERSION: '5.0.x' + NETCORE_TEST_VERSION_3_1: '3.1.x' + NETCORE_TEST_VERSION_2_1: '2.1.x' RunPoliCheck: 'false' PathToCsproj: 'src/CommunityToolkit/Xamarin.CommunityToolkit/Xamarin.CommunityToolkit.csproj' PathToMarkupCsproj: 'src/Markup/Xamarin.CommunityToolkit.Markup/Xamarin.CommunityToolkit.Markup.csproj' + PathToUnitTestCsproj: 'src/CommunityToolkit/Xamarin.CommunityToolkit.UnitTests/Xamarin.CommunityToolkit.UnitTests.csproj' PathToSln: 'samples/XCT.Sample.sln' resources: @@ -68,6 +70,21 @@ jobs: pool: vmImage: windows-2019 steps: + - task: UseDotNet@2 + displayName: 'Install .NET SDK' + inputs: + version: $(NETCORE_VERSION) + includePreviewVersions: false + - task: UseDotNet@2 + displayName: 'Install .NET 3.1 Test SDK' + inputs: + version: $(NETCORE_TEST_VERSION_3_1) + includePreviewVersions: false + - task: UseDotNet@2 + displayName: 'Install .NET 2.1 Test SDK' + inputs: + version: $(NETCORE_TEST_VERSION_2_1) + includePreviewVersions: false # if this is a tagged build, then update the version number - powershell: | $buildSourceBranch = "$(Build.SourceBranch)" @@ -112,12 +129,10 @@ jobs: # command: 'custom' # custom: 'nuget' # arguments: 'push --source https://nuget.pkg.github.com/xamarin/index.json --api-key $(GitHub.NuGet.Token) "$(Build.ArtifactStagingDirectory)\nuget\*.nupkg"' - - task: DotNetCoreCLI@2 - displayName: Run Tests + - task: CmdLine@2 + displayName: 'Run Unit Tests' inputs: - command: test - projects: '**/*.UnitTests.csproj' - arguments: '--configuration Release --collect "Code coverage"' + script: dotnet test $(PathToUnitTestCsproj) -c Release --collect "Code coverage" -p:BuildInParallel=false # publish the packages - task: PublishBuildArtifacts@1 displayName: 'Publish Unsigned NuGets' @@ -161,27 +176,28 @@ jobs: # displayName: Switch to the latest Xcode # restore, build and pack the packages - task: UseDotNet@2 - displayName: 'Use .Net Core sdk' + displayName: 'Install .NET SDK' inputs: version: $(NETCORE_VERSION) includePreviewVersions: false - task: UseDotNet@2 - displayName: 'Use .Net Core sdk' + displayName: 'Install .NET 3.1 Test SDK' inputs: - version: $(NETCORE_TEST_VERSION) + version: $(NETCORE_TEST_VERSION_3_1) includePreviewVersions: false - - task: MSBuild@1 - displayName: Build Solution + - task: UseDotNet@2 + displayName: 'Install .NET 2.1 Test SDK' inputs: - solution: $(PathToCsproj) - configuration: Release - msbuildArguments: '/restore /t:Build /p:ContinuousIntegrationBuild=true /p:Deterministic=false' - - task: MSBuild@1 - displayName: Pack NuGets + version: $(NETCORE_TEST_VERSION_2_1) + includePreviewVersions: false + - task: CmdLine@2 + displayName: 'Build Solution' inputs: - solution: $(PathToCsproj) - configuration: Release - msbuildArguments: '/t:Pack /p:PackageVersion=$(NugetPackageVersion) /p:PackageOutputPath="$(Build.ArtifactStagingDirectory)/nuget"' + script: 'mono /Applications/Visual\ studio.app/Contents/Resources/lib/monodevelop/bin/MSBuild/Current/bin/MSBuild.dll $(PathToCsproj) /p:Configuration=Release /restore /t:Build /p:ContinuousIntegrationBuild=true /p:Deterministic=false' + - task: CmdLine@2 + displayName: 'Pack NuGets' + inputs: + script: 'mono /Applications/Visual\ studio.app/Contents/Resources/lib/monodevelop/bin/MSBuild/Current/bin/MSBuild.dll $(PathToCsproj) /p:Configuration=Release /t:Pack /p:PackageVersion=$(NugetPackageVersion) /p:PackageOutputPath="$(Build.ArtifactStagingDirectory)/nuget"' - ${{ if eq(variables['System.TeamProject'], 'devdiv') }}: - template: sign-artifacts/jobs/v2.yml@internal-templates diff --git a/samples/XCT.Sample.Android/SplashActivity.cs b/samples/XCT.Sample.Android/SplashActivity.cs index c9d8f69df..2883e4e55 100644 --- a/samples/XCT.Sample.Android/SplashActivity.cs +++ b/samples/XCT.Sample.Android/SplashActivity.cs @@ -9,7 +9,7 @@ namespace Xamarin.CommunityToolkit.Sample.Droid [Activity(Label = "XamarinCommunityToolkitSample", Icon = "@mipmap/icon", Theme = "@style/SplashTheme", MainLauncher = true, ConfigurationChanges = ConfigChanges.ScreenSize | ConfigChanges.Orientation)] public class SplashActivity : AppCompatActivity { - protected override void OnCreate(Bundle savedInstanceState) + protected override void OnCreate(Bundle? savedInstanceState) { base.OnCreate(savedInstanceState); var intent = new Intent(this, typeof(MainActivity)); diff --git a/samples/XCT.Sample.UWP/App.xaml.cs b/samples/XCT.Sample.UWP/App.xaml.cs index 2a60dbd76..29871212c 100644 --- a/samples/XCT.Sample.UWP/App.xaml.cs +++ b/samples/XCT.Sample.UWP/App.xaml.cs @@ -85,7 +85,7 @@ protected override void OnLaunched(LaunchActivatedEventArgs e) /// /// The Frame which failed navigation /// Details about the navigation failure - void OnNavigationFailed(object sender, NavigationFailedEventArgs e) + void OnNavigationFailed(object? sender, NavigationFailedEventArgs e) { throw new Exception("Failed to load Page " + e.SourcePageType.FullName); } @@ -97,7 +97,7 @@ void OnNavigationFailed(object sender, NavigationFailedEventArgs e) /// /// The source of the suspend request. /// Details about the suspend request. - void OnSuspending(object sender, SuspendingEventArgs e) + void OnSuspending(object? sender, SuspendingEventArgs e) { var deferral = e.SuspendingOperation.GetDeferral(); diff --git a/samples/XCT.Sample.iOS/Renderers/NoLineNavigationRenderer.cs b/samples/XCT.Sample.iOS/Renderers/NoLineNavigationRenderer.cs index f1231d834..af6c3fc37 100644 --- a/samples/XCT.Sample.iOS/Renderers/NoLineNavigationRenderer.cs +++ b/samples/XCT.Sample.iOS/Renderers/NoLineNavigationRenderer.cs @@ -25,8 +25,11 @@ public override void ViewWillAppear(bool animated) // Newest iOS version fix - trycatch isn't optimal try { - NavigationBar.ScrollEdgeAppearance.ShadowImage = new UIKit.UIImage(); - NavigationBar.ScrollEdgeAppearance.ShadowColor = null; + if (NavigationBar.ScrollEdgeAppearance != null) + { + NavigationBar.ScrollEdgeAppearance.ShadowImage = new UIKit.UIImage(); + NavigationBar.ScrollEdgeAppearance.ShadowColor = null; + } } catch (Exception) { diff --git a/samples/XCT.Sample.sln b/samples/XCT.Sample.sln index fcf418bc7..eab396c70 100644 --- a/samples/XCT.Sample.sln +++ b/samples/XCT.Sample.sln @@ -18,9 +18,9 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.CommunityToolkit.Sa EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{F695F5E8-420F-475F-A4CF-F5BB3FA6E818}" ProjectSection(SolutionItems) = preProject - .editorconfig = .editorconfig - Directory.Build.props = Directory.Build.props - Xamarin.CommunityToolkit.ruleset = Xamarin.CommunityToolkit.ruleset + ..\.editorconfig = ..\.editorconfig + ..\Directory.Build.props = ..\Directory.Build.props + ..\Xamarin.CommunityToolkit.ruleset = ..\Xamarin.CommunityToolkit.ruleset EndProjectSection EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Xamarin.CommunityToolkit.Sample.WPF", "XCT.Sample.WPF\Xamarin.CommunityToolkit.Sample.WPF.csproj", "{C4D6CD2D-8DF4-4D46-936C-1AB31C87B5EA}" @@ -62,6 +62,7 @@ Global {8B80BFA6-7B19-4DE7-BD97-7D84194AD0C2}.Debug|x86.Build.0 = Debug|Any CPU {8B80BFA6-7B19-4DE7-BD97-7D84194AD0C2}.Release|Any CPU.ActiveCfg = Release|Any CPU {8B80BFA6-7B19-4DE7-BD97-7D84194AD0C2}.Release|Any CPU.Build.0 = Release|Any CPU + {8B80BFA6-7B19-4DE7-BD97-7D84194AD0C2}.Release|Any CPU.Deploy.0 = Release|Any CPU {8B80BFA6-7B19-4DE7-BD97-7D84194AD0C2}.Release|ARM.ActiveCfg = Release|Any CPU {8B80BFA6-7B19-4DE7-BD97-7D84194AD0C2}.Release|ARM.Build.0 = Release|Any CPU {8B80BFA6-7B19-4DE7-BD97-7D84194AD0C2}.Release|iPhone.ActiveCfg = Release|Any CPU @@ -191,6 +192,8 @@ Global {91C748B4-E9ED-4543-880A-26747B03DE3A}.Debug|x86.Build.0 = Debug|x86 {91C748B4-E9ED-4543-880A-26747B03DE3A}.Debug|x86.Deploy.0 = Debug|x86 {91C748B4-E9ED-4543-880A-26747B03DE3A}.Release|Any CPU.ActiveCfg = Release|x86 + {91C748B4-E9ED-4543-880A-26747B03DE3A}.Release|Any CPU.Build.0 = Release|x86 + {91C748B4-E9ED-4543-880A-26747B03DE3A}.Release|Any CPU.Deploy.0 = Release|x86 {91C748B4-E9ED-4543-880A-26747B03DE3A}.Release|ARM.ActiveCfg = Release|ARM {91C748B4-E9ED-4543-880A-26747B03DE3A}.Release|ARM.Build.0 = Release|ARM {91C748B4-E9ED-4543-880A-26747B03DE3A}.Release|ARM.Deploy.0 = Release|ARM diff --git a/samples/XCT.Sample/App.xaml.cs b/samples/XCT.Sample/App.xaml.cs index b5a234305..6e2137b3b 100644 --- a/samples/XCT.Sample/App.xaml.cs +++ b/samples/XCT.Sample/App.xaml.cs @@ -1,4 +1,5 @@ -using Xamarin.CommunityToolkit.Helpers; +using System.Globalization; +using Xamarin.CommunityToolkit.Helpers; using Xamarin.CommunityToolkit.Sample.Pages; using Xamarin.CommunityToolkit.Sample.Resx; using Xamarin.Forms.PlatformConfiguration; @@ -14,6 +15,7 @@ public App() LocalizationResourceManager.Current.PropertyChanged += (sender, e) => AppResources.Culture = LocalizationResourceManager.Current.CurrentCulture; LocalizationResourceManager.Current.Init(AppResources.ResourceManager); + LocalizationResourceManager.Current.CurrentCulture = new CultureInfo("en"); InitializeComponent(); MainPage = new BaseNavigationPage(new WelcomePage()); diff --git a/samples/XCT.Sample/Helpers/RelayCommand.cs b/samples/XCT.Sample/Helpers/RelayCommand.cs index 453460545..d82836760 100644 --- a/samples/XCT.Sample/Helpers/RelayCommand.cs +++ b/samples/XCT.Sample/Helpers/RelayCommand.cs @@ -7,25 +7,21 @@ namespace Xamarin.CommunityToolkit.Sample { public class RelayCommand : ICommand { - readonly Action execute; - readonly Func asyncExecute; + readonly Action? execute; + readonly Func? asyncExecute; + readonly Func? canExecute; - Func canExecute; int executingCount; - public RelayCommand(Action execute, Func canExecute = null) + public RelayCommand(Action execute, Func? canExecute = null) { - if (execute == null) - throw new ArgumentNullException(nameof(execute)); - this.execute = execute; + this.execute = execute ?? throw new ArgumentNullException(nameof(execute)); this.canExecute = canExecute; } - protected RelayCommand(Func execute, Func canExecute = null) // This ctor is protected here and public in a derived class, to allow simple initialization like new RelayCommand(MyMethod) without errors due to ambiguity + protected RelayCommand(Func execute, Func? canExecute = null) // This ctor is protected here and public in a derived class, to allow simple initialization like new RelayCommand(MyMethod) without errors due to ambiguity { - if (execute == null) - throw new ArgumentNullException(nameof(execute)); - asyncExecute = execute; + asyncExecute = execute ?? throw new ArgumentNullException(nameof(execute)); this.canExecute = canExecute; } @@ -34,7 +30,7 @@ public RelayCommand(Action execute, Func canExecute = null) /// /// Ignored; this is the paremeterless command class /// - public bool CanExecute(object parameter = null) + public bool CanExecute(object? parameter = null) { try { @@ -47,15 +43,12 @@ public bool CanExecute(object parameter = null) } } - public event EventHandler CanExecuteChanged; + public event EventHandler? CanExecuteChanged; - public void RaiseCanExecuteChanged() - { - CanExecuteChanged?.Invoke(this, EventArgs.Empty); - } + public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty); // Asynchronous command handling based on http://stackoverflow.com/a/31595509/6043538 - public async void Execute(object parameter = null) + public async void Execute(object? parameter = null) { var couldExecuteBeforeExecute = CanExecute(); if (!couldExecuteBeforeExecute) @@ -70,8 +63,10 @@ public async void Execute(object parameter = null) { if (execute != null) execute(); - else + else if (asyncExecute != null) await asyncExecute(); + else + throw new Exception("Execute is null"); } catch (Exception ex) { @@ -89,31 +84,30 @@ public async void Execute(object parameter = null) public class RelayCommandAsync : RelayCommand { - public RelayCommandAsync(Func execute, Func canExecute = null) - : base(execute, canExecute) { } // This ctor is public here and protected in the base class, to allow simple initialization like new RelayCommandAsync(MyMethod) without errors due to ambiguity + public RelayCommandAsync(Func execute, Func? canExecute = null) + : base(execute, canExecute) + { + // This ctor is public here and protected in the base class, to allow simple initialization like new RelayCommandAsync(MyMethod) without errors due to ambiguity + } } public class RelayCommand : ICommand { - readonly Action execute; - readonly Func asyncExecute; + readonly Action? execute; + readonly Func? asyncExecute; + readonly Func? canExecute; - Func canExecute; int executingCount; - public RelayCommand(Action execute, Func canExecute = null) + public RelayCommand(Action execute, Func? canExecute = null) { - if (execute == null) - throw new ArgumentNullException(nameof(execute)); - this.execute = execute; + this.execute = execute ?? throw new ArgumentNullException(nameof(execute)); this.canExecute = canExecute; } - protected RelayCommand(Func execute, Func canExecute = null) // This ctor is protected here and public in a derived class, to allow simple initialization like new RelayCommand(MyMethod) without errors due to ambiguity + protected RelayCommand(Func execute, Func? canExecute = null) // This ctor is protected here and public in a derived class, to allow simple initialization like new RelayCommand(MyMethod) without errors due to ambiguity { - if (execute == null) - throw new ArgumentNullException(nameof(execute)); - asyncExecute = execute; + asyncExecute = execute ?? throw new ArgumentNullException(nameof(execute)); this.canExecute = canExecute; } @@ -122,11 +116,11 @@ public RelayCommand(Action execute, Func canExecut /// /// /// - public bool CanExecute(object parameter = null) + public bool CanExecute(object? parameter = null) { try { - return canExecute != null ? canExecute((TParameter)parameter) : executingCount == 0; + return canExecute != null ? canExecute((TParameter?)parameter) : executingCount == 0; } catch (Exception ex) { @@ -135,12 +129,9 @@ public bool CanExecute(object parameter = null) } } - public event EventHandler CanExecuteChanged; + public event EventHandler? CanExecuteChanged; - public void RaiseCanExecuteChanged() - { - CanExecuteChanged?.Invoke(this, EventArgs.Empty); - } + public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty); // Asynchronous command handling based on http://stackoverflow.com/a/31595509/6043538 public async void Execute(object parameterAsObject) @@ -159,13 +150,11 @@ public async void Execute(object parameterAsObject) var parameter = (TParameter)parameterAsObject; if (execute != null) - { execute(parameter); - } - else - { + else if (asyncExecute != null) await asyncExecute(parameter); - } + else + throw new Exception("Execute is null"); } catch (Exception ex) { @@ -183,7 +172,10 @@ public async void Execute(object parameterAsObject) public class RelayCommandAsync : RelayCommand { - public RelayCommandAsync(Func execute, Func canExecute = null) - : base(execute, canExecute) { } // This ctor is public here and protected in the base class, to allow simple initialization like new RelayCommandAsync(MyMethod) without errors due to ambiguity + public RelayCommandAsync(Func execute, Func? canExecute = null) + : base(execute, canExecute) + { + // This ctor is public here and protected in the base class, to allow simple initialization like new RelayCommandAsync(MyMethod) without errors due to ambiguity + } } } \ No newline at end of file diff --git a/samples/XCT.Sample/Helpers/XLog.cs b/samples/XCT.Sample/Helpers/XLog.cs index 88dd1c65c..79e77b027 100644 --- a/samples/XCT.Sample/Helpers/XLog.cs +++ b/samples/XCT.Sample/Helpers/XLog.cs @@ -13,7 +13,7 @@ namespace Xamarin.CommunityToolkit.Sample /// public static class XLog { - static string rootFolderPattern = null; + static string? rootFolderPattern = null; #if WINDOWS_UWP static LoggingChannel loggingChannel; #endif @@ -22,7 +22,7 @@ public static class XLog /// Call this before logging starts. /// /// Should match the top folder name(s) within the source control repository, e.g. @"\MobileRealtimePush\MobileRealtimePush\". Any folders before the first match of this pattern are omitted from the logged source file paths - public static void Init(string rootFolderPattern = null) + public static void Init(string? rootFolderPattern = null) { XLog.rootFolderPattern = rootFolderPattern; #if WINDOWS_UWP @@ -46,10 +46,10 @@ public static void Init(string rootFolderPattern = null) /// supplied by compiler, no need to specify in code unless you want to pass a deeper call context [Conditional("DEBUG")] public static void Debug( - object data = null, - string tag = null, - [CallerMemberName] string memberName = null, - [CallerFilePath] string sourceFilePath = null, + object? data = null, + string? tag = null, + [CallerMemberName] string? memberName = null, + [CallerFilePath] string? sourceFilePath = null, [CallerLineNumber] int sourceLineNumber = -1) { var message = FormatLogString(data, tag, memberName, sourceFilePath, sourceLineNumber); @@ -75,10 +75,10 @@ public static void Init(string rootFolderPattern = null) /// supplied by compiler, no need to specify in code unless you want to pass a deeper call context [Conditional("TRACE")] public static void Trace( - object data = null, - string tag = null, - [CallerMemberName] string memberName = null, - [CallerFilePath] string sourceFilePath = null, + object? data = null, + string? tag = null, + [CallerMemberName] string? memberName = null, + [CallerFilePath] string? sourceFilePath = null, [CallerLineNumber] int sourceLineNumber = -1) { var message = FormatLogString(data, tag, memberName, sourceFilePath, sourceLineNumber); @@ -90,9 +90,9 @@ public static void Init(string rootFolderPattern = null) #endif } - public static string TruncateAt(this string s, int maxLength, string truncatedSuffix = "...") => s?.Length <= maxLength ? s : s.Substring(0, maxLength) + truncatedSuffix; + public static string TruncateAt(this string? s, int maxLength, string truncatedSuffix = "...") => s?.Length <= maxLength ? s : s?.Substring(0, maxLength) + truncatedSuffix; - static string FormatLogString(object data = null, string tag = null, string memberName = null, string sourceFilePath = null, int sourceLineNumber = -1) + static string FormatLogString(object? data, string? tag, string? memberName, string? sourceFilePath, int sourceLineNumber) { var line = new StringBuilder(); @@ -121,7 +121,7 @@ static string FormatLogString(object data = null, string tag = null, string memb line.Append(dataString); } - if (!string.IsNullOrEmpty(sourceFilePath)) + if (sourceFilePath != null && !string.IsNullOrEmpty(sourceFilePath)) { if (!string.IsNullOrEmpty(rootFolderPattern)) { diff --git a/samples/XCT.Sample/Pages/AboutPage.xaml.cs b/samples/XCT.Sample/Pages/AboutPage.xaml.cs index 2c1826452..40374940d 100644 --- a/samples/XCT.Sample/Pages/AboutPage.xaml.cs +++ b/samples/XCT.Sample/Pages/AboutPage.xaml.cs @@ -1,5 +1,4 @@ using System; -using Xamarin.CommunityToolkit.Sample.ViewModels; namespace Xamarin.CommunityToolkit.Sample.Pages { @@ -8,7 +7,7 @@ public partial class AboutPage : BasePage public AboutPage() => InitializeComponent(); - async void OnCloseClicked(object sender, EventArgs e) + async void OnCloseClicked(object? sender, EventArgs e) => await Navigation.PopModalAsync(); } } \ No newline at end of file diff --git a/samples/XCT.Sample/Pages/Base/BaseNavigationPage.cs b/samples/XCT.Sample/Pages/Base/BaseNavigationPage.cs index 758b1e85e..cd61318df 100644 --- a/samples/XCT.Sample/Pages/Base/BaseNavigationPage.cs +++ b/samples/XCT.Sample/Pages/Base/BaseNavigationPage.cs @@ -9,6 +9,7 @@ public class BaseNavigationPage : XF.NavigationPage public BaseNavigationPage(XF.Page root) : base(root) { + On().SetPrefersHomeIndicatorAutoHidden(true); On().SetModalPresentationStyle(UIModalPresentationStyle.FormSheet); On().DisableTranslucentNavigationBar(); On().SetHideNavigationBarSeparator(true); diff --git a/samples/XCT.Sample/Pages/Base/BasePage.cs b/samples/XCT.Sample/Pages/Base/BasePage.cs index 8e7a5071f..fc558e1ec 100644 --- a/samples/XCT.Sample/Pages/Base/BasePage.cs +++ b/samples/XCT.Sample/Pages/Base/BasePage.cs @@ -1,21 +1,34 @@ using System; +using System.Threading.Tasks; using System.Windows.Input; using Xamarin.CommunityToolkit.ObjectModel; using Xamarin.CommunityToolkit.Sample.Models; using Xamarin.Forms; +using Xamarin.Forms.PlatformConfiguration; +using Xamarin.Forms.PlatformConfiguration.iOSSpecific; namespace Xamarin.CommunityToolkit.Sample.Pages { public class BasePage : ContentPage { - public BasePage() => - NavigateCommand = CommandFactory.Create(sectionModel => Navigation.PushAsync(PreparePage(sectionModel))); + public BasePage() + { + On().SetPrefersHomeIndicatorAutoHidden(true); + + NavigateCommand = CommandFactory.Create(sectionModel => + { + if (sectionModel != null) + return Navigation.PushAsync(PreparePage(sectionModel)); + + return Task.CompletedTask; + }); + } public Color DetailColor { get; set; } public ICommand NavigateCommand { get; } - Page PreparePage(SectionModel model) + Forms.Page PreparePage(SectionModel model) { var page = (BasePage)Activator.CreateInstance(model.Type); page.Title = model.Title; diff --git a/samples/XCT.Sample/Pages/Behaviors/AnimationBehaviorPage.xaml b/samples/XCT.Sample/Pages/Behaviors/AnimationBehaviorPage.xaml index ed8116e73..a4f582554 100644 --- a/samples/XCT.Sample/Pages/Behaviors/AnimationBehaviorPage.xaml +++ b/samples/XCT.Sample/Pages/Behaviors/AnimationBehaviorPage.xaml @@ -48,7 +48,7 @@ -