Skip to content

Commit 3e3d434

Browse files
VisualMelonMrJul
andauthored
Set TimePicker.Time seconds to zero when UseSeconds is False (#17251)
* Set TimePickerPresenter.Time seconds component to zero when UseSeconds is false * Remove unneeded PART_FirstSpace annotation from TimePickerPresenter --------- Co-authored-by: Julien Lebosquain <[email protected]>
1 parent 0bd90d8 commit 3e3d434

File tree

2 files changed

+154
-6
lines changed

2 files changed

+154
-6
lines changed

src/Avalonia.Controls/DateTimePickers/TimePickerPresenter.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@ namespace Avalonia.Controls
2828
[TemplatePart("PART_PeriodSelector", typeof(DateTimePickerPanel), IsRequired = true)]
2929
[TemplatePart("PART_PeriodUpButton", typeof(RepeatButton))]
3030
[TemplatePart("PART_PickerContainer", typeof(Grid), IsRequired = true)]
31-
[TemplatePart("PART_ThirdSpacer", typeof(Rectangle), IsRequired = true)]
31+
[TemplatePart("PART_SecondSpacer", typeof(Rectangle), IsRequired = true)]
32+
[TemplatePart("PART_ThirdSpacer", typeof(Rectangle), IsRequired = true)]
3233
public class TimePickerPresenter : PickerPresenterBase
3334
{
3435
/// <summary>
@@ -241,7 +242,7 @@ protected override void OnConfirmed()
241242
hr = per == 1 ? (hr == 12) ? 12 : hr + 12 : per == 0 && hr == 12 ? 0 : hr;
242243
}
243244

244-
SetCurrentValue(TimeProperty, new TimeSpan(hr, min, sec));
245+
SetCurrentValue(TimeProperty, new TimeSpan(hr, min, UseSeconds ? sec : 0));
245246

246247
base.OnConfirmed();
247248
}
@@ -262,14 +263,14 @@ private void InitPicker()
262263
_minuteSelector!.MaximumValue = 59;
263264
_minuteSelector.MinimumValue = 0;
264265
_minuteSelector.Increment = MinuteIncrement;
265-
_minuteSelector.SelectedValue = Time.Minutes;
266266
_minuteSelector.ItemFormat = "mm";
267+
_minuteSelector.SelectedValue = Time.Minutes;
267268

268269
_secondSelector!.MaximumValue = 59;
269270
_secondSelector.MinimumValue = 0;
270271
_secondSelector.Increment = SecondIncrement;
271-
_secondSelector.SelectedValue = Time.Seconds;
272272
_secondSelector.ItemFormat = "ss";
273+
_secondSelector.SelectedValue = Time.Seconds;
273274

274275
_periodSelector!.MaximumValue = 1;
275276
_periodSelector.MinimumValue = 0;

tests/Avalonia.Controls.UnitTests/TimePickerTests.cs

Lines changed: 149 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
using System;
22
using System.Linq;
33
using System.Reactive.Subjects;
4+
using Avalonia.Controls.Primitives;
45
using Avalonia.Controls.Shapes;
56
using Avalonia.Controls.Templates;
67
using Avalonia.Data;
@@ -94,6 +95,67 @@ public void UseSeconds_Equals_False_Should_Hide_Seconds()
9495
}
9596
}
9697

98+
[Fact]
99+
public void UseSeconds_Equals_False_Should_Have_Zero_Seconds()
100+
{
101+
using (UnitTestApplication.Start(Services))
102+
{
103+
TimePicker timePicker = new TimePicker()
104+
{
105+
UseSeconds = false,
106+
Template = CreateTemplate(includePopup: true)
107+
};
108+
timePicker.ApplyTemplate();
109+
110+
var desc = timePicker.GetVisualDescendants();
111+
Assert.True(desc.Count() > 2);
112+
113+
// find button
114+
Assert.True(desc.ElementAt(1) is Button);
115+
var btn = (Button)desc.ElementAt(1);
116+
117+
Assert.True(desc.ElementAt(2) is Popup);
118+
var popup = (Popup)desc.ElementAt(2);
119+
120+
Assert.True(popup.Child is TimePickerPresenter);
121+
var timePickerPresenter = (TimePickerPresenter)popup.Child;
122+
123+
var panel = (Panel)timePickerPresenter.VisualChildren[0];
124+
var acceptBtn = (Button)panel.VisualChildren[0];
125+
126+
Assert.False(popup.IsOpen);
127+
btn.PerformClick();
128+
Assert.True(popup.IsOpen);
129+
Assert.False(timePickerPresenter.UseSeconds);
130+
131+
acceptBtn.PerformClick();
132+
133+
Assert.Equal(0, timePickerPresenter.Time.Seconds);
134+
Assert.Equal(0, timePicker.SelectedTime?.Seconds);
135+
}
136+
}
137+
138+
[Fact]
139+
public void TimePickerPresenter_UseSeconds_Equals_False_Should_Have_Zero_Seconds()
140+
{
141+
using (UnitTestApplication.Start(Services))
142+
{
143+
TimePickerPresenter timePickerPresenter = new TimePickerPresenter()
144+
{
145+
UseSeconds = false,
146+
Template = CreatePickerTemplate(),
147+
};
148+
timePickerPresenter.ApplyTemplate();
149+
150+
var panel = (Panel)timePickerPresenter.VisualChildren[0];
151+
var acceptBtn = (Button)panel.VisualChildren[0];
152+
153+
acceptBtn.PerformClick();
154+
155+
Assert.Equal(0, timePickerPresenter.Time.Seconds);
156+
}
157+
}
158+
97159
[Fact]
98160
public void SelectedTime_null_Should_Use_Placeholders()
99161
{
@@ -219,14 +281,15 @@ public void SelectedTime_EnableDataValidation()
219281
textShaperImpl: new HeadlessTextShaperStub(),
220282
renderInterface: new HeadlessPlatformRenderInterface());
221283

222-
private static IControlTemplate CreateTemplate()
284+
private static IControlTemplate CreateTemplate(bool includePopup = false)
223285
{
224286
return new FuncControlTemplate((control, scope) =>
225287
{
226288
var layoutRoot = new Grid
227289
{
228290
Name = "LayoutRoot"
229291
}.RegisterInNameScope(scope);
292+
230293
//Skip contentpresenter
231294
var flyoutButton = new Button
232295
{
@@ -288,7 +351,7 @@ private static IControlTemplate CreateTemplate()
288351
Name = "PART_SecondColumnDivider"
289352
}.RegisterInNameScope(scope);
290353
Grid.SetColumn(secondSpacer, 3);
291-
354+
292355
var thirdSpacer = new Rectangle
293356
{
294357
Name = "PART_ThirdColumnDivider"
@@ -298,8 +361,92 @@ private static IControlTemplate CreateTemplate()
298361
contentGrid.Children.AddRange(new Control[] { firstPickerHost, firstSpacer, secondPickerHost, secondSpacer, thirdPickerHost, thirdSpacer, fourthPickerHost });
299362
flyoutButton.Content = contentGrid;
300363
layoutRoot.Children.Add(flyoutButton);
364+
365+
if (includePopup)
366+
{
367+
var popup = new Popup
368+
{
369+
Name = "PART_Popup"
370+
}.RegisterInNameScope(scope);
371+
372+
var pickerPresenter = new TimePickerPresenter
373+
{
374+
Name = "PART_PickerPresenter",
375+
Template = CreatePickerTemplate()
376+
}.RegisterInNameScope(scope);
377+
pickerPresenter.ApplyTemplate();
378+
379+
popup.Child = pickerPresenter;
380+
381+
layoutRoot.Children.Add(popup);
382+
}
383+
301384
return layoutRoot;
302385
});
303386
}
387+
388+
private static IControlTemplate CreatePickerTemplate()
389+
{
390+
return new FuncControlTemplate((control, scope) =>
391+
{
392+
var acceptButton = new Button
393+
{
394+
Name = "PART_AcceptButton"
395+
}.RegisterInNameScope(scope);
396+
397+
var hourSelector = new DateTimePickerPanel
398+
{
399+
Name = "PART_HourSelector",
400+
PanelType = DateTimePickerPanelType.Hour,
401+
}.RegisterInNameScope(scope);
402+
403+
var minuteSelector = new DateTimePickerPanel
404+
{
405+
Name = "PART_MinuteSelector",
406+
PanelType = DateTimePickerPanelType.Minute,
407+
}.RegisterInNameScope(scope);
408+
409+
var secondHost = new Panel
410+
{
411+
Name = "PART_SecondHost"
412+
}.RegisterInNameScope(scope);
413+
414+
var secondSelector = new DateTimePickerPanel
415+
{
416+
Name = "PART_SecondSelector",
417+
PanelType = DateTimePickerPanelType.Second,
418+
}.RegisterInNameScope(scope);
419+
420+
var periodHost = new Panel
421+
{
422+
Name = "PART_PeriodHost"
423+
}.RegisterInNameScope(scope);
424+
425+
var periodSelector = new DateTimePickerPanel
426+
{
427+
Name = "PART_PeriodSelector",
428+
PanelType = DateTimePickerPanelType.TimePeriod,
429+
}.RegisterInNameScope(scope);
430+
431+
var pickerContainer = new Grid
432+
{
433+
Name = "PART_PickerContainer"
434+
}.RegisterInNameScope(scope);
435+
436+
var secondSpacer = new Rectangle
437+
{
438+
Name = "PART_SecondSpacer"
439+
}.RegisterInNameScope(scope);
440+
441+
var thirdSpacer = new Rectangle
442+
{
443+
Name = "PART_ThirdSpacer"
444+
}.RegisterInNameScope(scope);
445+
446+
var contentPanel = new StackPanel();
447+
contentPanel.Children.AddRange(new Control[] { acceptButton, hourSelector, minuteSelector, secondHost, secondSelector, periodHost, periodSelector, pickerContainer, secondSpacer, thirdSpacer });
448+
return contentPanel;
449+
});
450+
}
304451
}
305452
}

0 commit comments

Comments
 (0)