Skip to content

Commit

Permalink
fix: dispatch safearea inset setter logic
Browse files Browse the repository at this point in the history
  • Loading branch information
kazo0 committed May 10, 2023
1 parent bc0617c commit 22b90c1
Show file tree
Hide file tree
Showing 3 changed files with 201 additions and 35 deletions.
148 changes: 148 additions & 0 deletions src/Uno.Toolkit.RuntimeTests/Tests/SafeAreaTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Uno.Disposables;
using Uno.Toolkit.RuntimeTests.Extensions;
using Uno.Toolkit.RuntimeTests.Helpers;
using Uno.Toolkit.RuntimeTests.Tests.TestPages;
using Uno.Toolkit.UI;
using Uno.UI.RuntimeTests;
using Windows.System;

#if __IOS__
using UIKit;
#endif

#if IS_WINUI
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Windows.UI.ViewManagement;
#else
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Markup;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;
using Windows.UI;
using Windows.UI.ViewManagement;
using Microsoft.VisualStudio.TestTools.UnitTesting;

#endif

namespace Uno.Toolkit.RuntimeTests.Tests
{
[TestClass]
[RunsOnUIThread]
internal partial class SafeAreaTests
{
#if __ANDROID__
[TestMethod]
public async Task Translucent_SystemBars()
{
using var _ = UseFullWindow();
using var __ = UseTranslucentBars();

var redGrid = new Grid
{
Background = new SolidColorBrush(Colors.Red),
};

var blueGrid = new Grid
{
Background = new SolidColorBrush(Colors.Blue),
};

redGrid.Children.Add(blueGrid);

SafeArea.SetInsets(redGrid, SafeArea.InsetMask.VisibleBounds);

await UnitTestUIContentHelperEx.SetContentAndWait(redGrid);

var visibleBounds = ApplicationView.GetForCurrentView().VisibleBounds;
var blueRect = blueGrid.TransformToVisual(null).TransformBounds(new Windows.Foundation.Rect(0, 0, blueGrid.ActualWidth, blueGrid.ActualHeight));
var redRect = redGrid.TransformToVisual(null).TransformBounds(new Windows.Foundation.Rect(0, 0, redGrid.ActualWidth, redGrid.ActualHeight));

var statusBarHeight = visibleBounds.Top - redRect.Top;
var navAreaHeight = redRect.Bottom - visibleBounds.Bottom;

Assert.AreEqual(blueRect.Top, statusBarHeight);
Assert.AreEqual(blueRect.Bottom, redRect.Bottom - navAreaHeight);
Assert.AreEqual(redGrid.Padding.Top, statusBarHeight);
Assert.AreEqual(redGrid.Padding.Bottom, navAreaHeight);
}

[TestMethod]
public async Task Translucent_SystemBars_Dynamic()
{
using var _ = UseFullWindow();

var redGrid = new Grid
{
Background = new SolidColorBrush(Colors.Red),
};

var blueGrid = new Grid
{
Background = new SolidColorBrush(Colors.Blue),
};

redGrid.Children.Add(blueGrid);
SafeArea.SetInsets(redGrid, SafeArea.InsetMask.VisibleBounds);

await UnitTestUIContentHelperEx.SetContentAndWait(redGrid);

var blueWithOpaqueBars = blueGrid.TransformToVisual(null).TransformBounds(new Windows.Foundation.Rect(0, 0, blueGrid.ActualWidth, blueGrid.ActualHeight));
var windowWithOpaqueBars = redGrid.TransformToVisual(null).TransformBounds(new Windows.Foundation.Rect(0, 0, redGrid.ActualWidth, redGrid.ActualHeight));
var visibleBoundsWithOpaqueBars = ApplicationView.GetForCurrentView().VisibleBounds;

using var __ = UseTranslucentBars();

await UnitTestsUIContentHelper.WaitForIdle();

var blueWithTranslucentBars = blueGrid.TransformToVisual(null).TransformBounds(new Windows.Foundation.Rect(0, 0, blueGrid.ActualWidth, blueGrid.ActualHeight));
var windowWithTranslucentBars = redGrid.TransformToVisual(null).TransformBounds(new Windows.Foundation.Rect(0, 0, redGrid.ActualWidth, redGrid.ActualHeight));
var visibleBoundsWithTranslucentBars = ApplicationView.GetForCurrentView().VisibleBounds;

var statusBarHeight = windowWithOpaqueBars.Top - windowWithTranslucentBars.Top;
var navAreaHeight = windowWithTranslucentBars.Bottom - windowWithOpaqueBars.Bottom;

Assert.AreEqual(blueWithOpaqueBars, blueWithTranslucentBars);
Assert.AreEqual(blueWithTranslucentBars.Top, statusBarHeight);
Assert.AreEqual(blueWithTranslucentBars.Bottom, windowWithTranslucentBars.Bottom - navAreaHeight);
Assert.AreEqual(redGrid.Padding.Top, statusBarHeight);
Assert.AreEqual(redGrid.Padding.Bottom, navAreaHeight);
}


private IDisposable UseTranslucentBars()
{
var activity = Uno.UI.ContextHelper.Current as Android.App.Activity;
activity?.Window?.AddFlags(Android.Views.WindowManagerFlags.TranslucentNavigation | Android.Views.WindowManagerFlags.TranslucentStatus);

return Disposable.Create(() =>
{
activity?.Window?.ClearFlags(Android.Views.WindowManagerFlags.TranslucentNavigation | Android.Views.WindowManagerFlags.TranslucentStatus);
});
}
#endif

private IDisposable UseFullWindow()
{
UnitTestsUIContentHelper.UseActualWindowRoot = true;
UnitTestsUIContentHelper.SaveOriginalContent();

return Disposable.Create(() =>
{
UnitTestsUIContentHelper.RestoreOriginalContent();
UnitTestsUIContentHelper.UseActualWindowRoot = false;
});
}
}
}
66 changes: 41 additions & 25 deletions src/Uno.Toolkit.UI/Controls/SafeArea/SafeArea.cs
Original file line number Diff line number Diff line change
Expand Up @@ -247,8 +247,6 @@ private static Rect GetVisibleBounds(Rect? safeAreaOverride = null, bool withSof
// the InputRect to align with the VisibleBounds Rect.
if (totalOffset > 0)
{


var navBarOffset = (totalOffset - statusBarOffset);

inputRect.Height -= navBarOffset;
Expand Down Expand Up @@ -562,24 +560,33 @@ private void ApplyInsets(Thickness insets)
{
return;
}

if (_insetMode == InsetMode.Padding
&& !PaddingHelper.GetPadding(owner).Equals(insets)
&& PaddingHelper.SetPadding(owner, insets))
{
_appliedPadding = insets;
LogApplyInsets();
}
else if (_insetMode == InsetMode.Margin)
#if __ANDROID__
var dispatcher = owner.GetDispatcherCompat();
dispatcher.Schedule(() =>
#endif
{
if (!owner.Margin.Equals(insets))
if (_insetMode == InsetMode.Padding &&
!PaddingHelper.GetPadding(owner).Equals(insets) &&
PaddingHelper.SetPadding(owner, insets))
{
_appliedMargin = insets;
owner.Margin = insets;
_appliedPadding = insets;
LogApplyInsets();
}
}
else if (_insetMode == InsetMode.Margin)
{
if (!owner.Margin.Equals(insets))
{
_appliedMargin = insets;
owner.Margin = insets;
LogApplyInsets();
}
}
owner.InvalidateMeasure();
}
#if __ANDROID__
);
#endif
void LogApplyInsets()
{
if (_log.IsEnabled(LogLevel.Debug))
Expand Down Expand Up @@ -652,21 +659,30 @@ internal void OnInsetModeChanged(InsetMode oldValue, InsetMode newValue)

if (Owner is { } owner)
{
if (oldValue == InsetMode.Margin)
{
_appliedMargin = new Thickness(0);
owner.Margin = _originalMargin;
}
else if (oldValue == InsetMode.Padding)
#if __ANDROID__
var dispatcher = owner.GetDispatcherCompat();
dispatcher.Schedule(() =>
#endif
{
_appliedPadding = new Thickness(0);
PaddingHelper.SetPadding(owner, _originalPadding);
if (oldValue == InsetMode.Margin)
{
_appliedMargin = new Thickness(0);
owner.Margin = _originalMargin;
}
else if (oldValue == InsetMode.Padding)
{
_appliedPadding = new Thickness(0);
PaddingHelper.SetPadding(owner, _originalPadding);
}
owner.InvalidateMeasure();
}
#if __ANDROID__
);
#endif
}

UpdateInsets();
}
}

}
}
22 changes: 12 additions & 10 deletions src/Uno.Toolkit.UI/Helpers/DispatcherCompat.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,7 @@ public void Invoke(Priority priority, _Handler handler)
}
else
{
#if IS_WINUI
_impl.TryEnqueue(RemapPriority(priority), handler);
#else
_ = _impl.RunAsync(RemapPriority(priority), handler);
#endif
Schedule(priority, handler);
}
}

Expand All @@ -80,11 +76,7 @@ public Task RunAsync(Priority priority, _Handler handler)
{
var tcs = new TaskCompletionSource<object>();

#if IS_WINUI
_impl.TryEnqueue(RemapPriority(priority), () =>
#else
_ = _impl.RunAsync(RemapPriority(priority), () =>
#endif
Schedule(priority, () =>
{
try
{
Expand All @@ -100,4 +92,14 @@ public Task RunAsync(Priority priority, _Handler handler)
return tcs.Task;
}
}

public void Schedule(_Handler handler) => Schedule(default, handler);
public void Schedule(Priority priority, _Handler handler)
{
#if IS_WINUI
_impl.TryEnqueue(RemapPriority(priority), handler);
#else
_ = _impl.RunAsync(RemapPriority(priority), handler);
#endif
}
}

0 comments on commit 22b90c1

Please sign in to comment.