Skip to content

Commit

Permalink
chore: native timepicker- set -initial time
Browse files Browse the repository at this point in the history
  • Loading branch information
Kunal22shah committed Dec 2, 2024
1 parent dabd0a6 commit d609c32
Show file tree
Hide file tree
Showing 14 changed files with 288 additions and 53 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<Page
x:Class="Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml.Controls.StyleFlowToPopup"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

<Grid>
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="Red" />
</Style>
</Grid.Resources>
<StackPanel>
<TextBlock x:Name="InnerTextBlock" Text="Red foreground" />
</StackPanel>
<Popup x:Name="TestPopup">
<TextBlock x:Name="PopupContentTextBlock" Text="This should have red foreground too!" />
</Popup>
</Grid>
</Page>
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Controls.Primitives;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Input;
using Microsoft.UI.Xaml.Media;
using Microsoft.UI.Xaml.Navigation;
using Windows.Foundation;
using Windows.Foundation.Collections;

namespace Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml.Controls;

public sealed partial class StyleFlowToPopup : Page
{
public StyleFlowToPopup()
{
this.InitializeComponent();
}

public void ShowPopup() => TestPopup.IsOpen = true;

public TextBlock GridTextBlock => InnerTextBlock;

public TextBlock PopupTextBlock => PopupContentTextBlock;
}
33 changes: 25 additions & 8 deletions src/Uno.UI.RuntimeTests/Tests/Windows_UI_Xaml/Given_Style.cs
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using Uno.UI.Extensions;
using Microsoft.UI;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Controls;
using Microsoft.UI.Xaml.Data;
using Microsoft.UI.Xaml.Markup;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Microsoft.UI.Xaml.Media;
using Private.Infrastructure;
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Data;
using Uno.UI.RuntimeTests.Helpers;
using SamplesApp.UITests;
using Microsoft.UI.Xaml.Media;
using Uno.UI.RuntimeTests.Helpers;
using Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml.Controls;

namespace Uno.UI.RuntimeTests.Tests.Windows_UI_Xaml
{
Expand Down Expand Up @@ -88,5 +86,24 @@ public async Task When_ImplicitStyle()

Assert.AreEqual(HorizontalAlignment.Left, cc.HorizontalContentAlignment);
}

[TestMethod]
[RunsOnUIThread]
public async Task When_Style_Flows_To_Popup()
{
var page = new StyleFlowToPopup();
TestServices.WindowHelper.WindowContent = page;
await UITestHelper.Load(page);

var foreground = (SolidColorBrush)page.GridTextBlock.Foreground;
Assert.AreEqual(Microsoft.UI.Colors.Red, foreground.Color);

page.ShowPopup();

await TestServices.WindowHelper.WaitFor(() => VisualTreeHelper.GetOpenPopupsForXamlRoot(TestServices.WindowHelper.XamlRoot).Count > 0);

var popupForeground = (SolidColorBrush)page.PopupTextBlock.Foreground;
Assert.AreEqual(Microsoft.UI.Colors.Red, popupForeground.Color);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
using MUXControlsTestApp.Utilities;
using Private.Infrastructure;
using SamplesApp.UITests;
using Uno.UI.Extensions;
using Uno.UI.RuntimeTests.Helpers;
using Uno.UI.RuntimeTests.MUX.Helpers;

Expand Down Expand Up @@ -288,10 +289,86 @@ private async Task When_Native_Flyout_Theme(UIKit.UIUserInterfaceStyle expectedS
Assert.AreEqual(expectedStyle, nativeTimePicker.OverrideUserInterfaceStyle);
}
#endif
}
#if __IOS__ || __ANDROID__
[TestMethod]
public async Task When_Time_Uninitialized_Should_Display_Current_Time()
{
var timePicker = new Microsoft.UI.Xaml.Controls.TimePicker();
timePicker.Time = new TimeSpan(TimePicker.DEFAULT_TIME_TICKS);

class MyContext
{
public object StartTime => null;
var expectedCurrentTime = GetCurrentTime();

TestServices.WindowHelper.WindowContent = timePicker;
await TestServices.WindowHelper.WaitForLoaded(timePicker);

await DateTimePickerHelper.OpenDateTimePicker(timePicker);

var openFlyouts = FlyoutBase.OpenFlyouts;
var associatedFlyout = openFlyouts[0];
Assert.IsInstanceOfType(associatedFlyout, typeof(NativeTimePickerFlyout));

#if __ANDROID__
var nativeFlyout = (NativeTimePickerFlyout)associatedFlyout;

var dialog = nativeFlyout.GetNativeDialog();

var decorView = dialog.Window?.DecorView;
var timePickerView = FindTimePicker(decorView);

var displayedHour = timePickerView.GetHourCompat();
var displayedMinute = timePickerView.GetMinuteCompat();

Assert.AreEqual(expectedCurrentTime.Hours, displayedHour, "Hours should match the current time.");
Assert.AreEqual(expectedCurrentTime.Minutes, displayedMinute, "Minutes should match the current time.");
#elif __IOS__
var nativeFlyout = (NativeTimePickerFlyout)associatedFlyout;

var timeSelector = nativeFlyout.GetTimeSelector();
var displayedTime = timeSelector.Time;

Assert.AreEqual(expectedCurrentTime.Hours, displayedTime.Hours, "Hours should match the current time.");
Assert.AreEqual(expectedCurrentTime.Minutes, displayedTime.Minutes, "Minutes should match the current time.");
#endif
}

private TimeSpan GetCurrentTime()
{
var calendar = new global::Windows.Globalization.Calendar();
calendar.SetToNow();
var now = calendar.GetDateTime();
return new TimeSpan(now.Hour, now.Minute, now.Second);
}
#if __ANDROID__
private Android.Widget.TimePicker FindTimePicker(Android.Views.View root)
{
if (root is Android.Widget.TimePicker picker)
{
return picker;
}

if (root is not Android.Views.ViewGroup viewGroup)
{
return null;
}

for (var i = 0; i < viewGroup.ChildCount; i++)
{
var child = viewGroup.GetChildAt(i);
var result = FindTimePicker(child);
if (result != null)
{
return result;
}
}

return null;
}
#endif
#endif

class MyContext
{
public object StartTime => null;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,29 +78,10 @@ public void When_Closed_Immediately()
}

[TestMethod]
public async Task When_Child_Visual_Parents_Does_Not_Include_Popup()
public async Task When_Child_Visual_Parents_Do_Not_Include_Popup()
{
var popup = new Popup();
popup.XamlRoot = TestServices.WindowHelper.XamlRoot;
var button = new Button()
{
Content = "test"
};
popup.Child = button;
popup.IsOpen = true;
await WindowHelper.WaitForLoaded(button);
bool found = false;
DependencyObject current = popup.Child;
while (current != null)
{
if (current == popup)
{
found = true;
break;
}

current = VisualTreeHelper.GetParent(current);
}
var popup = await LoadAndOpenPopupWithButtonAsync();
bool found = SearchPopupChildAscendants(popup, element => element == popup, element => VisualTreeHelper.GetParent(element));

Assert.IsFalse(found);

Expand All @@ -110,6 +91,70 @@ public async Task When_Child_Visual_Parents_Does_Not_Include_Popup()

[TestMethod]
public async Task When_Child_Logical_Parents_Include_Popup()
{
var popup = await LoadAndOpenPopupWithButtonAsync();
bool found = SearchPopupChildAscendants(popup, element => element == popup, element => (element as FrameworkElement)?.Parent);

Assert.IsTrue(found);

// Should not throw
popup.IsOpen = false;
}

[TestMethod]
public async Task When_Child_Visual_Parent_Is_Canvas()
{
var popup = await LoadAndOpenPopupWithButtonAsync();
var child = (FrameworkElement)popup.Child;
var parent = VisualTreeHelper.GetParent(child);
Assert.IsInstanceOfType(parent, typeof(Canvas));
#if HAS_UNO // It is actually a PopupRoot, but it is internal in WinUI
Assert.IsInstanceOfType(parent, typeof(PopupRoot));
#endif

// Should not throw
popup.IsOpen = false;
}

[TestMethod]
public async Task When_Child_Logical_Parent_Is_Popup()
{
var popup = await LoadAndOpenPopupWithButtonAsync();
var child = (FrameworkElement)popup.Child;

Assert.AreEqual(popup, child.Parent);

// Should not throw
popup.IsOpen = false;
}

#if HAS_UNO // PopupPanel is Uno-specific
[TestMethod]
public async Task When_Child_Visual_Parents_Do_Not_Include_PopupPanel()
{
var popup = await LoadAndOpenPopupWithButtonAsync();
bool found = SearchPopupChildAscendants(popup, element => element is PopupPanel, VisualTreeHelper.GetParent);

Assert.IsFalse(found);

// Should not throw
popup.IsOpen = false;
}

[TestMethod]
public async Task When_Child_Logical_Parents_Do_Not_Include_PopupPanel()
{
var popup = await LoadAndOpenPopupWithButtonAsync();
bool found = SearchPopupChildAscendants(popup, element => element is PopupPanel, element => (element as FrameworkElement)?.Parent);

Assert.IsFalse(found);

// Should not throw
popup.IsOpen = false;
}
#endif

private async Task<Popup> LoadAndOpenPopupWithButtonAsync()
{
var popup = new Popup();
popup.XamlRoot = TestServices.WindowHelper.XamlRoot;
Expand All @@ -120,23 +165,23 @@ public async Task When_Child_Logical_Parents_Include_Popup()
popup.Child = button;
popup.IsOpen = true;
await WindowHelper.WaitForLoaded(button);
bool found = false;
DependencyObject current = button;
return popup;
}

private bool SearchPopupChildAscendants(Popup popup, Predicate<DependencyObject> predicate, Func<DependencyObject, DependencyObject> getParent)
{
DependencyObject current = popup.Child;
while (current != null)
{
if (current == popup)
if (predicate(current))
{
found = true;
break;
return true;
}

current = (current as FrameworkElement)?.Parent;
current = getParent(current);
}

Assert.IsTrue(found);

// Should not throw
popup.IsOpen = false;
return false;
}

[TestMethod]
Expand Down
9 changes: 9 additions & 0 deletions src/Uno.UI/UI/Xaml/Controls/Popup/Popup.Base.cs
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,15 @@ partial void OnIsOpenChangedPartial(bool oldIsOpen, bool newIsOpen)

partial void OnChildChangedPartial(UIElement oldChild, UIElement newChild)
{
if (oldChild is FrameworkElement oldChildFe && oldChildFe.LogicalParentOverride == this)
{
oldChildFe.SetLogicalParent(null);
}
if (newChild is FrameworkElement newChildFe)
{
newChildFe.SetLogicalParent(this);
}

if (oldChild is IDependencyObjectStoreProvider provider &&
provider.Store.ReadLocalValue(provider.Store.DataContextProperty) != DependencyProperty.UnsetValue)
{
Expand Down
4 changes: 0 additions & 4 deletions src/Uno.UI/UI/Xaml/Controls/Popup/PopupPanel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -231,17 +231,13 @@ Popup.PlacementTarget is not null
private protected override void OnLoaded()
{
base.OnLoaded();
// Set Parent to the Popup, to obtain the same behavior as UWP that the Popup (and therefore the rest of the main visual tree)
// is reachable by scaling the combined Parent/GetVisualParent() hierarchy.
this.SetLogicalParent(Popup);

this.XamlRoot.Changed += XamlRootChanged;
}

private protected override void OnUnloaded()
{
base.OnUnloaded();
this.SetLogicalParent(null);

if (XamlRoot is { } xamlRoot)
{
Expand Down
2 changes: 1 addition & 1 deletion src/Uno.UI/UI/Xaml/Controls/Popup/PopupRoot.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

namespace Microsoft.UI.Xaml.Controls.Primitives;

internal partial class PopupRoot : Panel
internal partial class PopupRoot : Canvas
{
private readonly List<ManagedWeakReference> _openPopups = new();

Expand Down
Loading

0 comments on commit d609c32

Please sign in to comment.