diff --git a/demo/Ursa.Demo/Pages/TimePickerDemo.axaml b/demo/Ursa.Demo/Pages/TimePickerDemo.axaml
new file mode 100644
index 0000000..219e8e1
--- /dev/null
+++ b/demo/Ursa.Demo/Pages/TimePickerDemo.axaml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
diff --git a/demo/Ursa.Demo/Pages/TimePickerDemo.axaml.cs b/demo/Ursa.Demo/Pages/TimePickerDemo.axaml.cs
new file mode 100644
index 0000000..330eb98
--- /dev/null
+++ b/demo/Ursa.Demo/Pages/TimePickerDemo.axaml.cs
@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace Ursa.Demo.Pages;
+
+public partial class TimePickerDemo : UserControl
+{
+ public TimePickerDemo()
+ {
+ InitializeComponent();
+ }
+}
\ No newline at end of file
diff --git a/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs b/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs
index 80b9f6a..f981fa6 100644
--- a/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs
+++ b/demo/Ursa.Demo/ViewModels/MainViewViewModel.cs
@@ -55,6 +55,7 @@ public class MainViewViewModel : ViewModelBase
MenuKeys.MenuKeySelectionList => new SelectionListDemoViewModel(),
MenuKeys.MenuKeySkeleton => new SkeletonDemoViewModel(),
MenuKeys.MenuKeyTagInput => new TagInputDemoViewModel(),
+ MenuKeys.MenuKeyTimePicker => new TimePickerDemoViewModel(),
MenuKeys.MenuKeyTimeline => new TimelineDemoViewModel(),
MenuKeys.MenuKeyTreeComboBox => new TreeComboBoxDemoViewModel(),
MenuKeys.MenuKeyTwoTonePathIcon => new TwoTonePathIconDemoViewModel(),
diff --git a/demo/Ursa.Demo/ViewModels/MenuViewModel.cs b/demo/Ursa.Demo/ViewModels/MenuViewModel.cs
index a1fcdb7..32066e6 100644
--- a/demo/Ursa.Demo/ViewModels/MenuViewModel.cs
+++ b/demo/Ursa.Demo/ViewModels/MenuViewModel.cs
@@ -43,6 +43,7 @@ public class MenuViewModel: ViewModelBase
new() { MenuHeader = "Skeleton", Key = MenuKeys.MenuKeySkeleton },
new() { MenuHeader = "TagInput", Key = MenuKeys.MenuKeyTagInput },
new() { MenuHeader = "Theme Toggler", Key = MenuKeys.MenuKeyThemeToggler },
+ new() { MenuHeader = "TimePicker", Key = MenuKeys.MenuKeyTimePicker },
new() { MenuHeader = "Timeline", Key = MenuKeys.MenuKeyTimeline },
new() { MenuHeader = "TreeComboBox", Key = MenuKeys.MenuKeyTreeComboBox },
new() { MenuHeader = "TwoTonePathIcon", Key = MenuKeys.MenuKeyTwoTonePathIcon},
@@ -86,6 +87,7 @@ public static class MenuKeys
public const string MenuKeySelectionList = "SelectionList";
public const string MenuKeyTagInput = "TagInput";
public const string MenuKeySkeleton = "Skeleton";
+ public const string MenuKeyTimePicker = "TimePicker";
public const string MenuKeyTimeline = "Timeline";
public const string MenuKeyTwoTonePathIcon = "TwoTonePathIcon";
public const string MenuKeyThemeToggler = "ThemeToggler";
diff --git a/demo/Ursa.Demo/ViewModels/TimePickerDemoViewModel.cs b/demo/Ursa.Demo/ViewModels/TimePickerDemoViewModel.cs
new file mode 100644
index 0000000..f115429
--- /dev/null
+++ b/demo/Ursa.Demo/ViewModels/TimePickerDemoViewModel.cs
@@ -0,0 +1,8 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+
+namespace Ursa.Demo.ViewModels;
+
+public class TimePickerDemoViewModel: ObservableObject
+{
+
+}
\ No newline at end of file
diff --git a/src/Ursa.Themes.Semi/Controls/TimePicker.axaml b/src/Ursa.Themes.Semi/Controls/TimePicker.axaml
new file mode 100644
index 0000000..779d93f
--- /dev/null
+++ b/src/Ursa.Themes.Semi/Controls/TimePicker.axaml
@@ -0,0 +1,270 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Ursa.Themes.Semi/Controls/_index.axaml b/src/Ursa.Themes.Semi/Controls/_index.axaml
index 6e25af2..0ceb9e3 100644
--- a/src/Ursa.Themes.Semi/Controls/_index.axaml
+++ b/src/Ursa.Themes.Semi/Controls/_index.axaml
@@ -32,6 +32,7 @@
+
diff --git a/src/Ursa.Themes.Semi/Locale/en-us.axaml b/src/Ursa.Themes.Semi/Locale/en-us.axaml
index 5ba89e2..11979d3 100644
--- a/src/Ursa.Themes.Semi/Locale/en-us.axaml
+++ b/src/Ursa.Themes.Semi/Locale/en-us.axaml
@@ -15,4 +15,5 @@
Dark
Light
System
+ Confirm
diff --git a/src/Ursa.Themes.Semi/Locale/zh-cn.axaml b/src/Ursa.Themes.Semi/Locale/zh-cn.axaml
index 2ffda25..d4a0054 100644
--- a/src/Ursa.Themes.Semi/Locale/zh-cn.axaml
+++ b/src/Ursa.Themes.Semi/Locale/zh-cn.axaml
@@ -15,4 +15,5 @@
暗色
亮色
跟随系统
+ 确认
diff --git a/src/Ursa/Controls/DateTimePicker/TimePicker.cs b/src/Ursa/Controls/DateTimePicker/TimePicker.cs
new file mode 100644
index 0000000..25e0ff8
--- /dev/null
+++ b/src/Ursa/Controls/DateTimePicker/TimePicker.cs
@@ -0,0 +1,264 @@
+using System.Globalization;
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.Metadata;
+using Avalonia.Controls.Primitives;
+using Avalonia.Data;
+using Avalonia.Input;
+using Avalonia.Interactivity;
+using Irihi.Avalonia.Shared.Contracts;
+using Irihi.Avalonia.Shared.Helpers;
+
+namespace Ursa.Controls;
+
+[TemplatePart(PART_TextBox, typeof(TextBox))]
+[TemplatePart(PART_Popup, typeof(Popup))]
+[TemplatePart(PART_Presenter, typeof(TimePickerPresenter))]
+[TemplatePart(PART_Button, typeof(Button))]
+public class TimePicker : TemplatedControl, IClearControl, IInnerContentControl, IPopupInnerContent
+{
+ public const string PART_TextBox = "PART_TextBox";
+ public const string PART_Popup = "PART_Popup";
+ public const string PART_Presenter = "PART_Presenter";
+ public const string PART_Button = "PART_Button";
+
+ public static readonly StyledProperty DisplayFormatProperty =
+ AvaloniaProperty.Register(
+ nameof(DisplayFormat), "HH:mm:ss");
+
+ public static readonly StyledProperty PanelFormatProperty = AvaloniaProperty.Register(
+ nameof(PanelFormat), "HH mm ss");
+
+ public static readonly StyledProperty SelectedTimeProperty =
+ AvaloniaProperty.Register(
+ nameof(SelectedTime));
+
+ public static readonly StyledProperty NeedConfirmationProperty = AvaloniaProperty.Register(
+ nameof(NeedConfirmation));
+
+ public static readonly StyledProperty