From 5a4b0589bd94c25115e35f53bb285f24a177f75f Mon Sep 17 00:00:00 2001 From: Murdo R Ergeaux Date: Sat, 12 Oct 2024 11:46:32 +0100 Subject: [PATCH] Set TimePickerPresenter.Time seconds component to zero when UseSeconds is false --- .../DateTimePickers/TimePickerPresenter.cs | 10 +- .../TimePickerTests.cs | 156 +++++++++++++++++- 2 files changed, 160 insertions(+), 6 deletions(-) diff --git a/src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs b/src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs index be5c2db6fab..082117ac6bd 100644 --- a/src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs +++ b/src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs @@ -28,7 +28,9 @@ namespace Avalonia.Controls [TemplatePart("PART_PeriodSelector", typeof(DateTimePickerPanel), IsRequired = true)] [TemplatePart("PART_PeriodUpButton", typeof(RepeatButton))] [TemplatePart("PART_PickerContainer", typeof(Grid), IsRequired = true)] - [TemplatePart("PART_ThirdSpacer", typeof(Rectangle), IsRequired = true)] + [TemplatePart("PART_FirstSpacer", typeof(Rectangle), IsRequired = true)] + [TemplatePart("PART_SecondSpacer", typeof(Rectangle), IsRequired = true)] + [TemplatePart("PART_ThirdSpacer", typeof(Rectangle), IsRequired = true)] public class TimePickerPresenter : PickerPresenterBase { /// @@ -241,7 +243,7 @@ protected override void OnConfirmed() hr = per == 1 ? (hr == 12) ? 12 : hr + 12 : per == 0 && hr == 12 ? 0 : hr; } - SetCurrentValue(TimeProperty, new TimeSpan(hr, min, sec)); + SetCurrentValue(TimeProperty, new TimeSpan(hr, min, UseSeconds ? sec : 0)); base.OnConfirmed(); } @@ -262,14 +264,14 @@ private void InitPicker() _minuteSelector!.MaximumValue = 59; _minuteSelector.MinimumValue = 0; _minuteSelector.Increment = MinuteIncrement; - _minuteSelector.SelectedValue = Time.Minutes; _minuteSelector.ItemFormat = "mm"; + _minuteSelector.SelectedValue = Time.Minutes; _secondSelector!.MaximumValue = 59; _secondSelector.MinimumValue = 0; _secondSelector.Increment = SecondIncrement; - _secondSelector.SelectedValue = Time.Seconds; _secondSelector.ItemFormat = "ss"; + _secondSelector.SelectedValue = Time.Seconds; _periodSelector!.MaximumValue = 1; _periodSelector.MinimumValue = 0; diff --git a/tests/Avalonia.Controls.UnitTests/TimePickerTests.cs b/tests/Avalonia.Controls.UnitTests/TimePickerTests.cs index db563ad4c54..221889eb10f 100644 --- a/tests/Avalonia.Controls.UnitTests/TimePickerTests.cs +++ b/tests/Avalonia.Controls.UnitTests/TimePickerTests.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using System.Reactive.Subjects; +using Avalonia.Controls.Primitives; using Avalonia.Controls.Shapes; using Avalonia.Controls.Templates; using Avalonia.Data; @@ -94,6 +95,67 @@ public void UseSeconds_Equals_False_Should_Hide_Seconds() } } + [Fact] + public void UseSeconds_Equals_False_Should_Have_Zero_Seconds() + { + using (UnitTestApplication.Start(Services)) + { + TimePicker timePicker = new TimePicker() + { + UseSeconds = false, + Template = CreateTemplate(includePopup: true) + }; + timePicker.ApplyTemplate(); + + var desc = timePicker.GetVisualDescendants(); + Assert.True(desc.Count() > 2); + + // find button + Assert.True(desc.ElementAt(1) is Button); + var btn = (Button)desc.ElementAt(1); + + Assert.True(desc.ElementAt(2) is Popup); + var popup = (Popup)desc.ElementAt(2); + + Assert.True(popup.Child is TimePickerPresenter); + var timePickerPresenter = (TimePickerPresenter)popup.Child; + + var panel = (Panel)timePickerPresenter.VisualChildren[0]; + var acceptBtn = (Button)panel.VisualChildren[0]; + + Assert.False(popup.IsOpen); + btn.PerformClick(); + Assert.True(popup.IsOpen); + Assert.False(timePickerPresenter.UseSeconds); + + acceptBtn.PerformClick(); + + Assert.Equal(0, timePickerPresenter.Time.Seconds); + Assert.Equal(0, timePicker.SelectedTime?.Seconds); + } + } + + [Fact] + public void TimePickerPresenter_UseSeconds_Equals_False_Should_Have_Zero_Seconds() + { + using (UnitTestApplication.Start(Services)) + { + TimePickerPresenter timePickerPresenter = new TimePickerPresenter() + { + UseSeconds = false, + Template = CreatePickerTemplate(), + }; + timePickerPresenter.ApplyTemplate(); + + var panel = (Panel)timePickerPresenter.VisualChildren[0]; + var acceptBtn = (Button)panel.VisualChildren[0]; + + acceptBtn.PerformClick(); + + Assert.Equal(0, timePickerPresenter.Time.Seconds); + } + } + [Fact] public void SelectedTime_null_Should_Use_Placeholders() { @@ -219,7 +281,7 @@ public void SelectedTime_EnableDataValidation() textShaperImpl: new HeadlessTextShaperStub(), renderInterface: new HeadlessPlatformRenderInterface()); - private static IControlTemplate CreateTemplate() + private static IControlTemplate CreateTemplate(bool includePopup = false) { return new FuncControlTemplate((control, scope) => { @@ -227,6 +289,7 @@ private static IControlTemplate CreateTemplate() { Name = "LayoutRoot" }.RegisterInNameScope(scope); + //Skip contentpresenter var flyoutButton = new Button { @@ -288,7 +351,7 @@ private static IControlTemplate CreateTemplate() Name = "PART_SecondColumnDivider" }.RegisterInNameScope(scope); Grid.SetColumn(secondSpacer, 3); - + var thirdSpacer = new Rectangle { Name = "PART_ThirdColumnDivider" @@ -298,8 +361,97 @@ private static IControlTemplate CreateTemplate() contentGrid.Children.AddRange(new Control[] { firstPickerHost, firstSpacer, secondPickerHost, secondSpacer, thirdPickerHost, thirdSpacer, fourthPickerHost }); flyoutButton.Content = contentGrid; layoutRoot.Children.Add(flyoutButton); + + if (includePopup) + { + var popup = new Popup + { + Name = "PART_Popup" + }.RegisterInNameScope(scope); + + var pickerPresenter = new TimePickerPresenter + { + Name = "PART_PickerPresenter", + Template = CreatePickerTemplate() + }.RegisterInNameScope(scope); + pickerPresenter.ApplyTemplate(); + + popup.Child = pickerPresenter; + + layoutRoot.Children.Add(popup); + } + return layoutRoot; }); } + + private static IControlTemplate CreatePickerTemplate() + { + return new FuncControlTemplate((control, scope) => + { + var acceptButton = new Button + { + Name = "PART_AcceptButton" + }.RegisterInNameScope(scope); + + var hourSelector = new DateTimePickerPanel + { + Name = "PART_HourSelector", + PanelType = DateTimePickerPanelType.Hour, + }.RegisterInNameScope(scope); + + var minuteSelector = new DateTimePickerPanel + { + Name = "PART_MinuteSelector", + PanelType = DateTimePickerPanelType.Minute, + }.RegisterInNameScope(scope); + + var secondHost = new Panel + { + Name = "PART_SecondHost" + }.RegisterInNameScope(scope); + + var secondSelector = new DateTimePickerPanel + { + Name = "PART_SecondSelector", + PanelType = DateTimePickerPanelType.Second, + }.RegisterInNameScope(scope); + + var periodHost = new Panel + { + Name = "PART_PeriodHost" + }.RegisterInNameScope(scope); + + var periodSelector = new DateTimePickerPanel + { + Name = "PART_PeriodSelector", + PanelType = DateTimePickerPanelType.TimePeriod, + }.RegisterInNameScope(scope); + + var pickerContainer = new Grid + { + Name = "PART_PickerContainer" + }.RegisterInNameScope(scope); + + var firstSpacer = new Rectangle + { + Name = "PART_FirstSpacer" + }.RegisterInNameScope(scope); + + var secondSpacer = new Rectangle + { + Name = "PART_SecondSpacer" + }.RegisterInNameScope(scope); + + var thirdSpacer = new Rectangle + { + Name = "PART_ThirdSpacer" + }.RegisterInNameScope(scope); + + var contentPanel = new StackPanel(); + contentPanel.Children.AddRange(new Control[] { acceptButton, hourSelector, minuteSelector, secondHost, secondSelector, periodHost, periodSelector, pickerContainer, firstSpacer, secondSpacer, thirdSpacer }); + return contentPanel; + }); + } } }