完成基本的 TimePicker

This commit is contained in:
polarboy 2024-09-04 11:27:44 +08:00
parent 14005e1d35
commit bb585e3dc1
6 changed files with 113 additions and 19 deletions

View File

@ -62,6 +62,7 @@ internal class FlyoutStateHelper : AvaloniaObject
public event EventHandler<EventArgs>? FlyoutAboutToShow;
public Func<Point, bool>? OpenFlyoutPredicate;
public Func<IPopupHostProvider, RawPointerEventArgs, bool>? ClickHideFlyoutPredicate;
private DispatcherTimer? _mouseEnterDelayTimer;
private DispatcherTimer? _mouseLeaveDelayTimer;
@ -258,7 +259,13 @@ internal class FlyoutStateHelper : AvaloniaObject
}
}
} else {
if (Flyout is IPopupHostProvider popupHostProvider) {
if (ClickHideFlyoutPredicate is not null) {
if (ClickHideFlyoutPredicate(popupHostProvider, pointerEventArgs)) {
HideFlyout();
}
} else {
if (popupHostProvider.PopupHost != pointerEventArgs.Root) {
HideFlyout();
}
@ -267,6 +274,7 @@ internal class FlyoutStateHelper : AvaloniaObject
}
}
}
}
private void DetectWhenToClosePopup(RawInputEventArgs args)
{

View File

@ -1,4 +1,5 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Primitives;
namespace AtomUI.Controls;
@ -15,4 +16,18 @@ internal class PickerIndicator : TemplatedControl
get => GetValue(IsInClearModeProperty);
set => SetValue(IsInClearModeProperty, value);
}
private IconButton? _clearButton;
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{
base.OnApplyTemplate(e);
_clearButton = e.NameScope.Get<IconButton>(PickerIndicatorTheme.ClearButtonPart);
if (_clearButton is not null) {
_clearButton.Click += (sender, args) =>
{
ClearRequest?.Invoke(this, EventArgs.Empty);
};
}
}
}

View File

@ -1,8 +1,10 @@
using AtomUI.Data;
using AtomUI.Controls.Utils;
using AtomUI.Data;
using AtomUI.Theme.Styling;
using AtomUI.Utils;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.Diagnostics;
using Avalonia.Controls.Primitives;
using Avalonia.Data;
using Avalonia.Input;
@ -162,9 +164,15 @@ public class TimePicker : LineEdit
_flyoutStateHelper.FlyoutAboutToShow += HandleFlyoutAboutToShow;
_flyoutStateHelper.FlyoutAboutToClose += HandleFlyoutAboutToClose;
_flyoutStateHelper.OpenFlyoutPredicate = FlyoutOpenPredicate;
_flyoutStateHelper.ClickHideFlyoutPredicate = ClickHideFlyoutPredicate;
}
private bool FlyoutOpenPredicate(Point position)
{
return PositionInEditKernel(position);
}
private bool PositionInEditKernel(Point position)
{
if (_textBoxInnerBox is not null) {
var pos = _textBoxInnerBox.TranslatePoint(new Point(0, 0), TopLevel.GetTopLevel(this)!);
@ -200,6 +208,17 @@ public class TimePicker : LineEdit
return false;
}
private bool ClickHideFlyoutPredicate(IPopupHostProvider hostProvider, RawPointerEventArgs args)
{
if (hostProvider.PopupHost != args.Root) {
if (!PositionInEditKernel(args.Position)) {
return true;
}
}
return false;
}
private void HandleFlyoutAboutToShow(object? sender, EventArgs args)
{
_currentValidSelected = false;
@ -208,7 +227,11 @@ public class TimePicker : LineEdit
private void HandleFlyoutAboutToClose(object? sender, EventArgs args)
{
if (!_currentValidSelected) {
Text = SelectedTime.ToString();
if (SelectedTime.HasValue) {
Text = DateTimeUtils.FormatTimeSpan(SelectedTime.Value, ClockIdentifier == "12HourClock");
} else {
Clear();
}
}
}
@ -222,6 +245,11 @@ public class TimePicker : LineEdit
base.OnApplyTemplate(e);
if (InnerRightContent is null) {
_pickerIndicator = new PickerIndicator();
_pickerIndicator.ClearRequest += (sender, args) =>
{
Clear();
SelectedTime = null;
};
InnerRightContent = _pickerIndicator;
}
if (_pickerFlyout is null) {
@ -261,6 +289,20 @@ public class TimePicker : LineEdit
}
}
protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs change)
{
base.OnPropertyChanged(change);
if (VisualRoot is not null) {
if (change.Property == SelectedTimeProperty) {
if (SelectedTime.HasValue) {
Text = DateTimeUtils.FormatTimeSpan(SelectedTime.Value, ClockIdentifier == "12HourClock");
} else {
Clear();
}
}
}
}
private void DetectIndicatorState(RawInputEventArgs args)
{
if (args is RawPointerEventArgs pointerEventArgs) {
@ -318,7 +360,7 @@ public class TimePicker : LineEdit
internal void NotifyTemporaryTimeSelected(TimeSpan selected)
{
Text = selected.ToString();
Text = DateTimeUtils.FormatTimeSpan(selected, ClockIdentifier == "12HourClock");
}
internal void NotifyConfirmed(TimeSpan value)

View File

@ -15,6 +15,7 @@ public class TimePickerFlyoutPresenter : FlyoutPresenter
private TimePickerPresenter? _timePickerPresenter;
private IDisposable? _disposable;
private Button? _confirmButton;
private Button? _nowButton;
public TimePickerFlyoutPresenter(TimePicker timePicker)
{
@ -27,6 +28,7 @@ public class TimePickerFlyoutPresenter : FlyoutPresenter
base.OnApplyTemplate(e);
_timePickerPresenter = e.NameScope.Get<TimePickerPresenter>(TimePickerFlyoutPresenterTheme.ContentPresenterPart);
_confirmButton = e.NameScope.Get<Button>(TimePickerFlyoutPresenterTheme.ConfirmButtonPart);
_nowButton = e.NameScope.Get<Button>(TimePickerFlyoutPresenterTheme.NowButtonPart);
if (_timePickerPresenter is not null) {
_timePickerPresenter.Confirmed += (sender, args) =>
{
@ -37,6 +39,16 @@ public class TimePickerFlyoutPresenter : FlyoutPresenter
if (_confirmButton is not null) {
_confirmButton.Click += HandleConfirmButtonClicked;
}
if (_nowButton is not null) {
_nowButton.Click += HandleNowButtonClicked;
}
}
private void HandleNowButtonClicked(object? sender, RoutedEventArgs args)
{
_timePickerPresenter?.NowConfirm();
TimePickerRef.ClosePickerFlyout();
}
private void HandleConfirmButtonClicked(object? sender, RoutedEventArgs args)

View File

@ -188,18 +188,8 @@ public class TimePickerPresenter : PickerPresenterBase
var selectedValue = CollectValue();
TemporaryTime = selectedValue;
if (IsShowHeader) {
var dateTime = DateTime.Today.Add(selectedValue);
if (ClockIdentifier == "12HourClock") {
var formatInfo = new DateTimeFormatInfo();
formatInfo.AMDesignator = LanguageResourceBinder.GetLangResource(TimePickerLangResourceKey.AMText)!;
formatInfo.PMDesignator = LanguageResourceBinder.GetLangResource(TimePickerLangResourceKey.PMText)!;
if (_headerText is not null) {
_headerText.Text = dateTime.ToString(@"hh:mm:ss tt", formatInfo);
}
} else {
if (_headerText is not null) {
_headerText.Text = dateTime.ToString(@"HH:mm:ss");
}
_headerText.Text = DateTimeUtils.FormatTimeSpan(selectedValue, ClockIdentifier == "12HourClock");
}
}
}
@ -261,6 +251,12 @@ public class TimePickerPresenter : PickerPresenterBase
base.OnConfirmed();
}
internal void NowConfirm()
{
SetCurrentValue(TimeProperty, DateTime.Now.TimeOfDay);
base.OnConfirmed();
}
internal void Confirm()
{
OnConfirmed();

View File

@ -0,0 +1,21 @@
using System.Globalization;
using AtomUI.Controls.TimePickerLang;
using AtomUI.Data;
namespace AtomUI.Controls.Utils;
internal static class DateTimeUtils
{
public static string FormatTimeSpan(TimeSpan value, bool is12HourClock = false)
{
var dateTime = DateTime.Today.Add(value);
if (is12HourClock) {
var formatInfo = new DateTimeFormatInfo();
formatInfo.AMDesignator = LanguageResourceBinder.GetLangResource(TimePickerLangResourceKey.AMText)!;
formatInfo.PMDesignator = LanguageResourceBinder.GetLangResource(TimePickerLangResourceKey.PMText)!;
return dateTime.ToString(@"hh:mm:ss tt", formatInfo);
}
return dateTime.ToString(@"HH:mm:ss");
}
}