diff --git a/src/AvaloniaInside.Shell/NavigationBar.cs b/src/AvaloniaInside.Shell/NavigationBar.cs index 29e00e2..15c1a22 100644 --- a/src/AvaloniaInside.Shell/NavigationBar.cs +++ b/src/AvaloniaInside.Shell/NavigationBar.cs @@ -19,6 +19,17 @@ public class NavigationBar : TemplatedControl private object? _pendingHeader; + public NavigationBar(ShellView shellView) + { + ShellView = shellView; + } + + public NavigationBar(Page page) + { + Page = page; + ShellView = page.Shell; + } + #region ShellView public static readonly StyledProperty ShellViewProperty = @@ -27,7 +38,20 @@ public class NavigationBar : TemplatedControl public ShellView? ShellView { get => GetValue(ShellViewProperty); - internal set => SetValue(ShellViewProperty, value); + private set => SetValue(ShellViewProperty, value); + } + + #endregion + + #region Page + + public static readonly StyledProperty PageProperty = + AvaloniaProperty.Register(nameof(Page)); + + public Page? Page + { + get => GetValue(PageProperty); + private set => SetValue(PageProperty, value); } #endregion @@ -119,28 +143,28 @@ public object? CurrentView #endregion - #region TopSafeSpace + #region SafePadding - public static readonly StyledProperty TopSafeSpaceProperty = - AvaloniaProperty.Register(nameof(TopSafeSpace)); + public static readonly StyledProperty SafePaddingProperty = + AvaloniaProperty.Register(nameof(SafePadding)); - public double TopSafeSpace + public Thickness SafePadding { - get => GetValue(TopSafeSpaceProperty); - set => SetValue(TopSafeSpaceProperty, value); + get => GetValue(SafePaddingProperty); + set => SetValue(SafePaddingProperty, value); } #endregion - #region TopSafePadding + #region PlatformHeight - public static readonly StyledProperty TopSafePaddingProperty = - AvaloniaProperty.Register(nameof(TopSafePadding)); + public static readonly StyledProperty PlatformHeightProperty = + AvaloniaProperty.Register(nameof(PlatformHeight), defaultValue: 36); - public Thickness TopSafePadding + public double PlatformHeight { - get => GetValue(TopSafePaddingProperty); - set => SetValue(TopSafePaddingProperty, value); + get => GetValue(PlatformHeightProperty); + set => SetValue(PlatformHeightProperty, value); } #endregion @@ -158,6 +182,110 @@ public bool ApplyTopSafePadding #endregion + #region ApplyLeftSafePadding + + public static readonly StyledProperty ApplyLeftSafePaddingProperty = + AvaloniaProperty.Register(nameof(ApplyLeftSafePadding), defaultValue: true); + + public bool ApplyLeftSafePadding + { + get => GetValue(ApplyLeftSafePaddingProperty); + set => SetValue(ApplyLeftSafePaddingProperty, value); + } + + #endregion + + #region ApplyRightSafePadding + + public static readonly StyledProperty ApplyRightSafePaddingProperty = + AvaloniaProperty.Register(nameof(ApplyRightSafePadding), defaultValue: true); + + public bool ApplyRightSafePadding + { + get => GetValue(ApplyRightSafePaddingProperty); + set => SetValue(ApplyRightSafePaddingProperty, value); + } + + #endregion + + #region TopSafeSpace + + public static readonly StyledProperty TopSafeSpaceProperty = + AvaloniaProperty.Register(nameof(TopSafeSpace)); + + public double TopSafeSpace + { + get => GetValue(TopSafeSpaceProperty); + set => SetValue(TopSafeSpaceProperty, value); + } + + #endregion + + #region TopSafePadding + + public static readonly StyledProperty TopSafePaddingProperty = + AvaloniaProperty.Register(nameof(TopSafePadding)); + + public Thickness TopSafePadding + { + get => GetValue(TopSafePaddingProperty); + set => SetValue(TopSafePaddingProperty, value); + } + + #endregion + + #region LeftSafeSpace + + public static readonly StyledProperty LeftSafeSpaceProperty = + AvaloniaProperty.Register(nameof(LeftSafeSpace)); + + public double LeftSafeSpace + { + get => GetValue(LeftSafeSpaceProperty); + set => SetValue(LeftSafeSpaceProperty, value); + } + + #endregion + + #region LeftSafePadding + + public static readonly StyledProperty LeftSafePaddingProperty = + AvaloniaProperty.Register(nameof(LeftSafePadding)); + + public Thickness LeftSafePadding + { + get => GetValue(LeftSafePaddingProperty); + set => SetValue(LeftSafePaddingProperty, value); + } + + #endregion + + #region RightSafeSpace + + public static readonly StyledProperty RightSafeSpaceProperty = + AvaloniaProperty.Register(nameof(RightSafeSpace)); + + public double RightSafeSpace + { + get => GetValue(RightSafeSpaceProperty); + set => SetValue(RightSafeSpaceProperty, value); + } + + #endregion + + #region RightSafePadding + + public static readonly StyledProperty RightSafePaddingProperty = + AvaloniaProperty.Register(nameof(RightSafePadding)); + + public Thickness RightSafePadding + { + get => GetValue(RightSafePaddingProperty); + set => SetValue(RightSafePaddingProperty, value); + } + + #endregion + #region Attached properties #region Item @@ -219,10 +347,17 @@ public static void SetVisible(AvaloniaObject element, bool parameter) => protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) { base.OnPropertyChanged(change); + if (change.Property == ShellViewProperty) { ShellViewUpdated(); } + else if (change.Property == SafePaddingProperty || + change.Property == ApplyTopSafePaddingProperty || + change.Property == PlatformHeightProperty) + { + UpdateSafePaddingSizes(); + } } protected override void OnLoaded(RoutedEventArgs e) @@ -231,6 +366,8 @@ protected override void OnLoaded(RoutedEventArgs e) if (_pendingHeader != null) UpdateView(_pendingHeader); + + UpdateSafePaddingSizes(); } protected virtual void ShellViewUpdated() @@ -240,12 +377,25 @@ protected virtual void ShellViewUpdated() _backCommand = shellView.BackCommand; _sideMenuCommand = shellView.SideMenuCommand; - this[!TopSafePaddingProperty] = shellView[!ShellView.TopSafePaddingProperty]; - this[!TopSafeSpaceProperty] = shellView[!ShellView.TopSafeSpaceProperty]; - this[!ApplyTopSafePaddingProperty] = shellView[!ShellView.ApplyTopSafePaddingProperty]; + this[!SafePaddingProperty] = shellView[!ShellView.SafePaddingProperty]; + + if (Page is { } page) + { + this[!ApplyTopSafePaddingProperty] = shellView[!ShellView.EnableSafeAreaForTopProperty]; + this[!ApplyLeftSafePaddingProperty] = shellView[!ShellView.EnableSafeAreaForLeftProperty]; + this[!ApplyRightSafePaddingProperty] = shellView[!ShellView.EnableSafeAreaForRightProperty]; - if (shellView.ContentView?.CurrentView is { } currentView) - UpdateView(currentView); + UpdateView(page); + } + else + { + this[!ApplyTopSafePaddingProperty] = shellView[!ShellView.ApplyTopSafePaddingProperty]; + this[!ApplyLeftSafePaddingProperty] = shellView[!ShellView.ApplyLeftSafePaddingProperty]; + this[!ApplyRightSafePaddingProperty] = shellView[!ShellView.ApplyRightSafePaddingProperty]; + + if (shellView.ContentView?.CurrentView is { } currentView) + UpdateView(currentView); + } } protected override void OnApplyTemplate(TemplateAppliedEventArgs e) @@ -261,6 +411,8 @@ protected override void OnApplyTemplate(TemplateAppliedEventArgs e) if (_pendingHeader != null) UpdateView(_pendingHeader); + + UpdateSafePaddingSizes(); } #endregion @@ -362,4 +514,20 @@ protected virtual void UpdateHeader(object? view, ContentControl itemPresenter) } #endregion + + #region Sizing + + protected virtual void UpdateSafePaddingSizes() + { + TopSafeSpace = SafePadding.Top; + TopSafePadding = new Thickness(0, SafePadding.Top, 0, 0); + LeftSafeSpace = SafePadding.Left; + LeftSafePadding = new Thickness(SafePadding.Left, 0, 0, 0); + RightSafeSpace = SafePadding.Right; + RightSafePadding = new Thickness(0, 0, SafePadding.Right, 0); + + Height = PlatformHeight + (ApplyTopSafePadding ? SafePadding.Top : 0); + } + + #endregion } diff --git a/src/AvaloniaInside.Shell/Page.cs b/src/AvaloniaInside.Shell/Page.cs index 22e3001..a64f275 100644 --- a/src/AvaloniaInside.Shell/Page.cs +++ b/src/AvaloniaInside.Shell/Page.cs @@ -39,6 +39,201 @@ public ShellView? Shell #endregion + #region SafePadding + + public static readonly StyledProperty SafePaddingProperty = + AvaloniaProperty.Register(nameof(SafePadding)); + + public Thickness SafePadding + { + get => GetValue(SafePaddingProperty); + set => SetValue(SafePaddingProperty, value); + } + + #endregion + + #region ApplyTopSafePadding + + public static readonly StyledProperty ApplyTopSafePaddingProperty = + AvaloniaProperty.Register(nameof(ApplyTopSafePadding), defaultValue: true); + + public bool ApplyTopSafePadding + { + get => GetValue(ApplyTopSafePaddingProperty); + set => SetValue(ApplyTopSafePaddingProperty, value); + } + + #endregion + + #region ApplyBottomSafePadding + + public static readonly StyledProperty ApplyBottomSafePaddingProperty = + AvaloniaProperty.Register(nameof(ApplyBottomSafePadding), defaultValue: true); + + public bool ApplyBottomSafePadding + { + get => GetValue(ApplyBottomSafePaddingProperty); + set => SetValue(ApplyBottomSafePaddingProperty, value); + } + + #endregion + + #region ApplyLeftSafePadding + + public static readonly StyledProperty ApplyLeftSafePaddingProperty = + AvaloniaProperty.Register(nameof(ApplyLeftSafePadding), defaultValue: true); + + public bool ApplyLeftSafePadding + { + get => GetValue(ApplyLeftSafePaddingProperty); + set => SetValue(ApplyLeftSafePaddingProperty, value); + } + + #endregion + + #region ApplyRightSafePadding + + public static readonly StyledProperty ApplyRightSafePaddingProperty = + AvaloniaProperty.Register(nameof(ApplyRightSafePadding), defaultValue: true); + + public bool ApplyRightSafePadding + { + get => GetValue(ApplyRightSafePaddingProperty); + set => SetValue(ApplyRightSafePaddingProperty, value); + } + + #endregion + + #region TopSafeSpace + + public static readonly StyledProperty TopSafeSpaceProperty = + AvaloniaProperty.Register(nameof(TopSafeSpace)); + + public double TopSafeSpace + { + get => GetValue(TopSafeSpaceProperty); + set => SetValue(TopSafeSpaceProperty, value); + } + + #endregion + + #region TopSafePadding + + public static readonly StyledProperty TopSafePaddingProperty = + AvaloniaProperty.Register(nameof(TopSafePadding)); + + public Thickness TopSafePadding + { + get => GetValue(TopSafePaddingProperty); + set => SetValue(TopSafePaddingProperty, value); + } + + #endregion + + #region BottomSafeSpace + + public static readonly StyledProperty BottomSafeSpaceProperty = + AvaloniaProperty.Register(nameof(BottomSafeSpace)); + + public double BottomSafeSpace + { + get => GetValue(BottomSafeSpaceProperty); + set => SetValue(BottomSafeSpaceProperty, value); + } + + #endregion + + #region BottomSafePadding + + public static readonly StyledProperty BottomSafePaddingProperty = + AvaloniaProperty.Register(nameof(BottomSafePadding)); + + public Thickness BottomSafePadding + { + get => GetValue(BottomSafePaddingProperty); + set => SetValue(BottomSafePaddingProperty, value); + } + + #endregion + + #region LeftSafeSpace + + public static readonly StyledProperty LeftSafeSpaceProperty = + AvaloniaProperty.Register(nameof(LeftSafeSpace)); + + public double LeftSafeSpace + { + get => GetValue(LeftSafeSpaceProperty); + set => SetValue(LeftSafeSpaceProperty, value); + } + + #endregion + + #region LeftSafePadding + + public static readonly StyledProperty LeftSafePaddingProperty = + AvaloniaProperty.Register(nameof(LeftSafePadding)); + + public Thickness LeftSafePadding + { + get => GetValue(LeftSafePaddingProperty); + set => SetValue(LeftSafePaddingProperty, value); + } + + #endregion + + #region RightSafeSpace + + public static readonly StyledProperty RightSafeSpaceProperty = + AvaloniaProperty.Register(nameof(RightSafeSpace)); + + public double RightSafeSpace + { + get => GetValue(RightSafeSpaceProperty); + set => SetValue(RightSafeSpaceProperty, value); + } + + #endregion + + #region RightSafePadding + + public static readonly StyledProperty RightSafePaddingProperty = + AvaloniaProperty.Register(nameof(RightSafePadding)); + + public Thickness RightSafePadding + { + get => GetValue(RightSafePaddingProperty); + set => SetValue(RightSafePaddingProperty, value); + } + + #endregion + + #region PageSafePadding + + public static readonly StyledProperty PageSafePaddingProperty = + AvaloniaProperty.Register(nameof(PageSafePadding)); + + public Thickness PageSafePadding + { + get => GetValue(PageSafePaddingProperty); + set => SetValue(PageSafePaddingProperty, value); + } + + #endregion + + #region TabSafePadding + + public static readonly StyledProperty TabSafePaddingProperty = + AvaloniaProperty.Register(nameof(TabSafePadding)); + + public Thickness TabSafePadding + { + get => GetValue(TabSafePaddingProperty); + set => SetValue(TabSafePaddingProperty, value); + } + + #endregion + #endregion #region Lifecycle @@ -64,6 +259,27 @@ protected override void OnLoaded(RoutedEventArgs e) base.OnLoaded(e); ApplyNavigationBar(); AttachedNavigationBar?.UpdateView(this); + + this[!ApplyTopSafePaddingProperty] = this[!ShellView.EnableSafeAreaForTopProperty]; + this[!ApplyBottomSafePaddingProperty] = this[!ShellView.EnableSafeAreaForBottomProperty]; + this[!ApplyLeftSafePaddingProperty] = this[!ShellView.EnableSafeAreaForLeftProperty]; + this[!ApplyRightSafePaddingProperty] = this[!ShellView.ApplyRightSafePaddingProperty]; + } + + protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change) + { + base.OnPropertyChanged(change); + if (change.Property == ShellProperty) + { + if (Shell != null) + { + this[!SafePaddingProperty] = Shell[!ShellView.SafePaddingProperty]; + } + } + else if (change.Property == SafePaddingProperty) + { + UpdateSafePaddingSizes(); + } } protected override void OnApplyTemplate(TemplateAppliedEventArgs e) @@ -84,10 +300,26 @@ private void ApplyNavigationBar() (type == NavigationBarAttachType.ToFirstHostThenPage && Chain?.Back is HostNavigationChain)) return; - _navigationBarPlaceHolder.Content = _navigationBar = new NavigationBar - { - ShellView = Shell - }; + _navigationBarPlaceHolder.Content = _navigationBar = new NavigationBar(this); + } + + #endregion + + #region Sizing + + protected virtual void UpdateSafePaddingSizes() + { + TopSafeSpace = SafePadding.Top; + TopSafePadding = new Thickness(0, SafePadding.Top, 0, 0); + BottomSafeSpace = SafePadding.Bottom; + BottomSafePadding = new Thickness(0, 0, 0, SafePadding.Bottom); + LeftSafeSpace = SafePadding.Left; + LeftSafePadding = new Thickness(SafePadding.Left, 0, 0, 0); + RightSafeSpace = SafePadding.Right; + RightSafePadding = new Thickness(0, 0, SafePadding.Right, 0); + + PageSafePadding = new Thickness(SafePadding.Left, 0, SafePadding.Right, SafePadding.Bottom); + } #endregion diff --git a/src/AvaloniaInside.Shell/Platform/PlatformSetup.cs b/src/AvaloniaInside.Shell/Platform/PlatformSetup.cs index 947d534..e686396 100644 --- a/src/AvaloniaInside.Shell/Platform/PlatformSetup.cs +++ b/src/AvaloniaInside.Shell/Platform/PlatformSetup.cs @@ -70,9 +70,7 @@ public static NavigationBarAttachType NavigationBarAttachType { get { - if (OperatingSystem.IsIOS()) - return NavigationBarAttachType.ToFirstHostThenPage; - return NavigationBarAttachType.ToShell; + return NavigationBarAttachType.ToFirstHostThenPage; } } } diff --git a/src/AvaloniaInside.Shell/ShellView.cs b/src/AvaloniaInside.Shell/ShellView.cs index f8cfd5c..4589c25 100644 --- a/src/AvaloniaInside.Shell/ShellView.cs +++ b/src/AvaloniaInside.Shell/ShellView.cs @@ -11,7 +11,6 @@ using Avalonia.Controls.Primitives; using Avalonia.Input; using Avalonia.Interactivity; -using Avalonia.Threading; using AvaloniaInside.Shell.Platform; using ReactiveUI; using Splat; @@ -70,6 +69,8 @@ public enum SideMenuBehaveType public ICommand SideMenuCommand { get; set; } + protected override Type StyleKeyOverride => typeof(ShellView); + #region ScreenSize private ScreenSizeType _screenSize = ScreenSizeType.Large; @@ -105,67 +106,95 @@ public ScreenSizeType ScreenSize #endregion - #region TopSafeSpace + #region DefaultPageTransition - public static readonly StyledProperty TopSafeSpaceProperty = - AvaloniaProperty.Register(nameof(TopSafeSpace)); + /// + /// Defines the property. + /// + public static readonly StyledProperty DefaultPageTransitionProperty = + AvaloniaProperty.Register( + nameof(DefaultPageTransition), + defaultValue: PlatformSetup.TransitionForPage); - public double TopSafeSpace + /// + /// Gets or sets the animation played when content appears and disappears. + /// + public IPageTransition? DefaultPageTransition { - get => GetValue(TopSafeSpaceProperty); - set => SetValue(TopSafeSpaceProperty, value); + get => GetValue(DefaultPageTransitionProperty); + set => SetValue(DefaultPageTransitionProperty, value); } #endregion - #region BottomSafeSpace + #region ModalPageTransition - public static readonly StyledProperty BottomSafeSpaceProperty = - AvaloniaProperty.Register(nameof(BottomSafeSpace)); + /// + /// Defines the property. + /// + public static readonly StyledProperty ModalPageTransitionProperty = + AvaloniaProperty.Register( + nameof(ModalPageTransition), + defaultValue: PlatformSetup.TransitionForModal); - public double BottomSafeSpace + /// + /// Gets or sets the animation played when content appears and disappears. + /// + public IPageTransition? ModalPageTransition { - get => GetValue(BottomSafeSpaceProperty); - set => SetValue(BottomSafeSpaceProperty, value); + get => GetValue(ModalPageTransitionProperty); + set => SetValue(ModalPageTransitionProperty, value); } #endregion - #region TopSafePadding + #region NavigationBarAttachType - public static readonly StyledProperty TopSafePaddingProperty = - AvaloniaProperty.Register(nameof(TopSafePadding)); + /// + /// Defines the property. + /// + public static readonly StyledProperty NavigationBarAttachTypeProperty = + AvaloniaProperty.Register( + nameof(NavigationBarAttachType), + defaultValue: PlatformSetup.NavigationBarAttachType); - public Thickness TopSafePadding + /// + /// Gets or sets the type of attach navigation bar. + /// + public NavigationBarAttachType NavigationBarAttachType { - get => GetValue(TopSafePaddingProperty); - set => SetValue(TopSafePaddingProperty, value); + get => GetValue(NavigationBarAttachTypeProperty); + set => SetValue(NavigationBarAttachTypeProperty, value); } #endregion - #region BottomSafePadding + #endregion + + #region Safe area properties + + #region SafePadding - public static readonly StyledProperty BottomSafePaddingProperty = - AvaloniaProperty.Register(nameof(BottomSafePadding)); + public static readonly StyledProperty SafePaddingProperty = + AvaloniaProperty.Register(nameof(SafePadding)); - public Thickness BottomSafePadding + public Thickness SafePadding { - get => GetValue(BottomSafePaddingProperty); - set => SetValue(BottomSafePaddingProperty, value); + get => GetValue(SafePaddingProperty); + set => SetValue(SafePaddingProperty, value); } #endregion - #region SafePadding + #region EnableSafeArea - public static readonly StyledProperty SafePaddingProperty = - AvaloniaProperty.Register(nameof(SafePadding)); + public static readonly StyledProperty EnableSafeAreaProperty = + AvaloniaProperty.Register(nameof(EnableSafeArea), defaultValue: true); - public Thickness SafePadding + public bool EnableSafeArea { - get => GetValue(SafePaddingProperty); - set => SetValue(SafePaddingProperty, value); + get => GetValue(EnableSafeAreaProperty); + set => SetValue(EnableSafeAreaProperty, value); } #endregion @@ -173,12 +202,12 @@ public Thickness SafePadding #region ApplyTopSafePadding public static readonly StyledProperty ApplyTopSafePaddingProperty = - AvaloniaProperty.Register(nameof(ApplyTopSafePadding), defaultValue: true); + AvaloniaProperty.Register(nameof(ApplyTopSafePadding), defaultValue: true); public bool ApplyTopSafePadding { - get => GetValue(ApplyTopSafePaddingProperty); - set => SetValue(ApplyTopSafePaddingProperty, value); + get => GetValue(ApplyTopSafePaddingProperty); + private set => SetValue(ApplyTopSafePaddingProperty, value); } #endregion @@ -186,75 +215,38 @@ public bool ApplyTopSafePadding #region ApplyBottomSafePadding public static readonly StyledProperty ApplyBottomSafePaddingProperty = - AvaloniaProperty.Register(nameof(ApplyBottomSafePadding), defaultValue: true); + AvaloniaProperty.Register(nameof(ApplyBottomSafePadding), defaultValue: true); public bool ApplyBottomSafePadding { - get => GetValue(ApplyBottomSafePaddingProperty); - set => SetValue(ApplyBottomSafePaddingProperty, value); - } - - #endregion - - #region DefaultPageTransition - - /// - /// Defines the property. - /// - public static readonly StyledProperty DefaultPageTransitionProperty = - AvaloniaProperty.Register( - nameof(DefaultPageTransition), - defaultValue: PlatformSetup.TransitionForPage); - - /// - /// Gets or sets the animation played when content appears and disappears. - /// - public IPageTransition? DefaultPageTransition - { - get => GetValue(DefaultPageTransitionProperty); - set => SetValue(DefaultPageTransitionProperty, value); + get => GetValue(ApplyBottomSafePaddingProperty); + private set => SetValue(ApplyBottomSafePaddingProperty, value); } #endregion - #region ModalPageTransition + #region ApplyLeftSafePadding - /// - /// Defines the property. - /// - public static readonly StyledProperty ModalPageTransitionProperty = - AvaloniaProperty.Register( - nameof(ModalPageTransition), - defaultValue: PlatformSetup.TransitionForModal); + public static readonly StyledProperty ApplyLeftSafePaddingProperty = + AvaloniaProperty.Register(nameof(ApplyLeftSafePadding), defaultValue: true); - /// - /// Gets or sets the animation played when content appears and disappears. - /// - public IPageTransition? ModalPageTransition + public bool ApplyLeftSafePadding { - get => GetValue(ModalPageTransitionProperty); - set => SetValue(ModalPageTransitionProperty, value); + get => GetValue(ApplyLeftSafePaddingProperty); + private set => SetValue(ApplyLeftSafePaddingProperty, value); } #endregion - #region NavigationBarAttachType + #region ApplyRightSafePadding - /// - /// Defines the property. - /// - public static readonly StyledProperty NavigationBarAttachTypeProperty = - AvaloniaProperty.Register( - nameof(NavigationBarAttachType), - defaultValue: PlatformSetup.NavigationBarAttachType); + public static readonly StyledProperty ApplyRightSafePaddingProperty = + AvaloniaProperty.Register(nameof(ApplyRightSafePadding), defaultValue: true); - /// - /// Gets or sets the type of attach navigation bar. - /// - public NavigationBarAttachType NavigationBarAttachType + public bool ApplyRightSafePadding { - get => GetValue(NavigationBarAttachTypeProperty); - set => SetValue(NavigationBarAttachTypeProperty, value); + get => GetValue(ApplyRightSafePaddingProperty); + private set => SetValue(ApplyRightSafePaddingProperty, value); } #endregion @@ -291,6 +283,34 @@ public static void SetEnableSafeAreaForBottom(AvaloniaObject element, bool param #endregion + #region EnableSafeAreaForLeft + + public static readonly AttachedProperty EnableSafeAreaForLeftProperty = + AvaloniaProperty.RegisterAttached("EnableSafeAreaForLeft", + defaultValue: true); + + public static bool GetEnableSafeAreaForLeft(AvaloniaObject element) => + element.GetValue(EnableSafeAreaForLeftProperty); + + public static void SetEnableSafeAreaForLeft(AvaloniaObject element, bool parameter) => + element.SetValue(EnableSafeAreaForLeftProperty, parameter); + + #endregion + + #region EnableSafeAreaForRight + + public static readonly AttachedProperty EnableSafeAreaForRightProperty = + AvaloniaProperty.RegisterAttached("EnableSafeAreaForRight", + defaultValue: true); + + public static bool GetEnableSafeAreaForRight(AvaloniaObject element) => + element.GetValue(EnableSafeAreaForRightProperty); + + public static void SetEnableSafeAreaForRight(AvaloniaObject element, bool parameter) => + element.SetValue(EnableSafeAreaForRightProperty, parameter); + + #endregion + #endregion #region Ctor and loading @@ -332,9 +352,10 @@ protected override void OnLoaded(RoutedEventArgs e) _loadedFlag = true; } - if (TopLevel.GetTopLevel(this) is { InsetsManager: { } insetsManager }) + if (EnableSafeArea && TopLevel.GetTopLevel(this) is { InsetsManager: { } insetsManager }) { insetsManager.DisplayEdgeToEdge = true; + insetsManager.SafeAreaChanged += (s, e) => OnSafeEdgeSetup(); } OnSafeEdgeSetup(); @@ -363,9 +384,6 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang case nameof(SmallScreenSideMenuMode): UpdateSideMenu(); break; - case nameof(SafePadding): - OnSafeEdgeSetup(); - break; } } @@ -375,11 +393,6 @@ private void SetupUi() UpdateSideMenu(); SetupNavigationBar(); - if (_navigationBar is { } navigationBar) - { - navigationBar.ShellView = this; - } - if (_splitView != null) { _splitView.PaneClosing += SplitViewOnPaneClosing; @@ -393,18 +406,15 @@ private void SetupUi() protected virtual void OnSafeEdgeSetup() { - Dispatcher.UIThread.InvokeAsync(async () => - { - await Task.Delay(100); + if (!EnableSafeArea) + { + return; + } - if (TopLevel.GetTopLevel(this) is { InsetsManager: { DisplayEdgeToEdge: true } insetsManager }) - SafePadding = insetsManager.SafeAreaPadding; + TopLevel.SetAutoSafeAreaPadding(this, false); - TopSafeSpace = SafePadding.Top; - TopSafePadding = new Thickness(0, SafePadding.Top, 0, 0); - BottomSafeSpace = SafePadding.Bottom; - BottomSafePadding = new Thickness(0, 0, 0, SafePadding.Bottom); - }); + if (TopLevel.GetTopLevel(this) is { InsetsManager: { DisplayEdgeToEdge: true } insetsManager }) + SafePadding = insetsManager.SafeAreaPadding; } private void SetupNavigationBar() @@ -413,10 +423,7 @@ private void SetupNavigationBar() NavigationBarAttachType == NavigationBarAttachType.ToShell && _navigationBar == null) { - _navigationBarPlaceHolder.Content = _navigationBar = new NavigationBar - { - ShellView = this - }; + _navigationBarPlaceHolder.Content = _navigationBar = new NavigationBar(this); } } @@ -447,7 +454,7 @@ public async Task PushViewAsync( await (_contentView?.PushViewAsync(view, navigateType, cancellationToken) ?? Task.CompletedTask); AttachedNavigationBar?.UpdateView(Navigator.CurrentChain?.Instance); SelectSideMenuItem(); - UpdateBindings(); + UpdateBinding(); UpdateSideMenu(); } @@ -457,12 +464,20 @@ public async Task RemoveViewAsync(object view, { await (_contentView?.RemoveViewAsync(view, navigateType, cancellationToken) ?? Task.CompletedTask); await (_modalView?.RemoveViewAsync(view, navigateType, cancellationToken) ?? Task.CompletedTask); + + SelectSideMenuItem(); + UpdateBinding(); + UpdateSideMenu(); } public async Task ClearStackAsync(CancellationToken cancellationToken) { await (_contentView?.ClearStackAsync(cancellationToken) ?? Task.CompletedTask); await (_modalView?.ClearStackAsync(cancellationToken) ?? Task.CompletedTask); + + SelectSideMenuItem(); + UpdateBinding(); + UpdateSideMenu(); } public Task ModalAsync(object instance, NavigateType navigateType, CancellationToken cancellationToken) => @@ -543,20 +558,24 @@ private void UpdateScreenSize(ScreenSizeType old, ScreenSizeType newScreen) UpdateSideMenu(); } - private void UpdateBindings() + protected virtual void UpdateBinding() { - var view = _contentView?.CurrentView; - if (view is StyledElement element) - { - this[!ApplyTopSafePaddingProperty] = element[!EnableSafeAreaForTopProperty]; - this[!ApplyBottomSafePaddingProperty] = element[!EnableSafeAreaForBottomProperty]; - } - else - { - ApplyTopSafePadding = true; - ApplyBottomSafePadding = true; - } - } + var view = _contentView?.CurrentView; + if (view is StyledElement element) + { + this[!ApplyTopSafePaddingProperty] = element[!EnableSafeAreaForTopProperty]; + this[!ApplyBottomSafePaddingProperty] = element[!EnableSafeAreaForBottomProperty]; + this[!ApplyLeftSafePaddingProperty] = element[!EnableSafeAreaForLeftProperty]; + this[!ApplyRightSafePaddingProperty] = element[!ApplyRightSafePaddingProperty]; + } + else + { + ApplyTopSafePadding = true; + ApplyBottomSafePadding = true; + ApplyLeftSafePadding = true; + ApplyRightSafePadding = true; + } + } #endregion } diff --git a/src/AvaloniaInside.Shell/TabPage.cs b/src/AvaloniaInside.Shell/TabPage.cs index d1dbb43..b494d08 100644 --- a/src/AvaloniaInside.Shell/TabPage.cs +++ b/src/AvaloniaInside.Shell/TabPage.cs @@ -249,4 +249,32 @@ static void SetPrivateDateTimePropertyValue(T member, string propName, object } #endregion + + #region Sizing + + protected override void UpdateSafePaddingSizes() + { + TopSafeSpace = SafePadding.Top; + TopSafePadding = new Thickness(0, SafePadding.Top, 0, 0); + BottomSafeSpace = SafePadding.Bottom; + BottomSafePadding = new Thickness(0, 0, 0, SafePadding.Bottom); + LeftSafeSpace = SafePadding.Left; + LeftSafePadding = new Thickness(SafePadding.Left, 0, 0, 0); + RightSafeSpace = SafePadding.Right; + RightSafePadding = new Thickness(0, 0, SafePadding.Right, 0); + + PageSafePadding = new Thickness( + TabStripPlacement != Dock.Left ? SafePadding.Left : 0, + 0, + TabStripPlacement != Dock.Right ? SafePadding.Right : 0, + TabStripPlacement != Dock.Bottom ? SafePadding.Bottom : 0); + + TabSafePadding = new Thickness( + TabStripPlacement != Dock.Right ? SafePadding.Left : 0, + 0, + TabStripPlacement != Dock.Left ? SafePadding.Right : 0, + TabStripPlacement != Dock.Top ? SafePadding.Bottom : 0); + } + + #endregion } diff --git a/src/AvaloniaInside.Shell/Theme/Default/NavigationBar.axaml b/src/AvaloniaInside.Shell/Theme/Default/NavigationBar.axaml index 5afe910..01b205b 100644 --- a/src/AvaloniaInside.Shell/Theme/Default/NavigationBar.axaml +++ b/src/AvaloniaInside.Shell/Theme/Default/NavigationBar.axaml @@ -12,26 +12,30 @@ Height="{TemplateBinding TopSafeSpace}" IsVisible="{TemplateBinding ApplyTopSafePadding}"> - - - - - - - - - - diff --git a/src/AvaloniaInside.Shell/Theme/Default/TabPage.axaml b/src/AvaloniaInside.Shell/Theme/Default/TabPage.axaml index 301c4cd..0b49c81 100644 --- a/src/AvaloniaInside.Shell/Theme/Default/TabPage.axaml +++ b/src/AvaloniaInside.Shell/Theme/Default/TabPage.axaml @@ -11,18 +11,18 @@ HorizontalAlignment="{TemplateBinding HorizontalAlignment}" VerticalAlignment="{TemplateBinding VerticalAlignment}"> - - + + + ItemsSource="{TemplateBinding ItemsSource}" /> @@ -32,7 +32,8 @@ + ItemsSource="{TemplateBinding ItemsSource}" + Padding="{TemplateBinding TabSafePadding}"> diff --git a/src/Example/ShellExample/ShellExample/Views/MainView.axaml b/src/Example/ShellExample/ShellExample/Views/MainView.axaml index 33cd087..2556243 100644 --- a/src/Example/ShellExample/ShellExample/Views/MainView.axaml +++ b/src/Example/ShellExample/ShellExample/Views/MainView.axaml @@ -1,107 +1,102 @@ - - - - - + + + + - DefaultPageTransition="{Binding CurrentTransition}"> - + - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - - + + + + + diff --git a/src/Example/ShellExample/ShellExample/Views/MainView.axaml.cs b/src/Example/ShellExample/ShellExample/Views/MainView.axaml.cs index 87b606e..363d716 100644 --- a/src/Example/ShellExample/ShellExample/Views/MainView.axaml.cs +++ b/src/Example/ShellExample/ShellExample/Views/MainView.axaml.cs @@ -1,9 +1,10 @@ using Avalonia.Controls; using Avalonia.Interactivity; +using AvaloniaInside.Shell; namespace ShellExample.Views; -public partial class MainView : UserControl +public partial class MainView : ShellView { public static MainView Current { get; private set; } diff --git a/src/Example/ShellExample/ShellExample/Views/MainWindow.axaml b/src/Example/ShellExample/ShellExample/Views/MainWindow.axaml index 24b5890..70ee737 100644 --- a/src/Example/ShellExample/ShellExample/Views/MainWindow.axaml +++ b/src/Example/ShellExample/ShellExample/Views/MainWindow.axaml @@ -8,19 +8,5 @@ Icon="/Assets/avalonia-logo.ico" Title="ShellExample" Width="450"> - - - - - - - - - - - - - - - - \ No newline at end of file + +