1 /* Copyright (c) 2021 Samsung Electronics Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
7 * http://www.apache.org/licenses/LICENSE-2.0
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
17 using Tizen.NUI.BaseComponents;
18 using System.Collections.Generic;
19 using System.Collections.ObjectModel;
20 using System.ComponentModel;
21 using System.Diagnostics.CodeAnalysis;
22 using System.Globalization;
23 using Tizen.NUI.Binding;
25 namespace Tizen.NUI.Components
28 /// TimeChangedEventArgs is a class to notify changed TimePicker value argument which will sent to user.
30 /// <since_tizen> 9 </since_tizen>
31 public class TimeChangedEventArgs : EventArgs
34 /// TimeChangedEventArgs default constructor.
35 /// <param name="time">time value of TimePicker.</param>
37 [EditorBrowsable(EditorBrowsableState.Never)]
38 public TimeChangedEventArgs(DateTime time)
44 /// TimeChangedEventArgs default constructor.
45 /// <returns>The current time value of TimePicker.</returns>
47 /// <since_tizen> 9 </since_tizen>
48 public DateTime Time { get; }
52 /// TimePicker is a class which provides a function that allows the user to select
53 /// a time through a scrolling motion by expressing the specified value as a list.
54 /// TimePicker expresses the current time using the locale information of the system.
56 /// <since_tizen> 9 </since_tizen>
57 public class TimePicker : Control
62 [EditorBrowsable(EditorBrowsableState.Never)]
63 public static readonly BindableProperty TimeProperty = BindableProperty.Create(nameof(Time), typeof(DateTime), typeof(TimePicker), default(DateTime), propertyChanged: (bindable, oldValue, newValue) =>
65 var instance = (TimePicker)bindable;
68 instance.InternalTime = (DateTime)newValue;
71 defaultValueCreator: (bindable) =>
73 var instance = (TimePicker)bindable;
74 return instance.InternalTime;
78 /// Is24HourViewProperty
80 [EditorBrowsable(EditorBrowsableState.Never)]
81 public static readonly BindableProperty Is24HourViewProperty = BindableProperty.Create(nameof(Is24HourView), typeof(bool), typeof(TimePicker), default(bool), propertyChanged: (bindable, oldValue, newValue) =>
83 var instance = (TimePicker)bindable;
86 instance.InternalIs24HourView = (bool)newValue;
89 defaultValueCreator: (bindable) =>
91 var instance = (TimePicker)bindable;
92 return instance.InternalIs24HourView;
96 private bool is24HourView;
97 private DateTime currentTime;
98 private String[] ampmText;
99 private Picker hourPicker;
100 private Picker minutePicker;
101 private Picker ampmPicker;
104 /// Creates a new instance of TimePicker.
106 /// <since_tizen> 9 </since_tizen>
109 SetKeyboardNavigationSupport(true);
113 /// Creates a new instance of TimePicker.
115 /// <param name="style">Creates TimePicker by special style defined in UX.</param>
116 /// <since_tizen> 9 </since_tizen>
117 public TimePicker(string style) : base(style)
119 SetKeyboardNavigationSupport(true);
123 /// Creates a new instance of TimePicker.
125 /// <param name="timePickerStyle">Creates TimePicker by style customized by user.</param>
126 /// <since_tizen> 9 </since_tizen>
127 public TimePicker(TimePickerStyle timePickerStyle) : base(timePickerStyle)
129 SetKeyboardNavigationSupport(true);
133 /// Dispose TimePicker and all children on it.
135 /// <param name="type">Dispose type.</param>
136 [EditorBrowsable(EditorBrowsableState.Never)]
137 protected override void Dispose(DisposeTypes type)
144 if (type == DisposeTypes.Explicit)
147 Utility.Dispose(hourPicker);
149 Remove(minutePicker);
150 Utility.Dispose(minutePicker);
153 Utility.Dispose(ampmPicker);
161 /// An event emitted when TimePicker value changed, user can subscribe or unsubscribe to this event handler.
163 /// <since_tizen> 9 </since_tizen>
164 public event EventHandler<TimeChangedEventArgs> TimeChanged;
167 /// The hour value of TimePicker.
169 /// <since_tizen> 9 </since_tizen>
174 return (DateTime)GetValue(TimeProperty);
178 SetValue(TimeProperty, value);
179 NotifyPropertyChanged();
182 private DateTime InternalTime
193 if (currentTime.Hour >= 12 && currentTime.Hour <= 23)
196 if (currentTime.Hour == 12) hourPicker.CurrentValue = currentTime.Hour;
197 else hourPicker.CurrentValue = currentTime.Hour - 12;
198 ampmPicker.CurrentValue = 2;
203 if (currentTime.Hour == 0) hourPicker.CurrentValue = 12;
204 else hourPicker.CurrentValue = currentTime.Hour;
205 ampmPicker.CurrentValue = 1;
208 else hourPicker.CurrentValue = currentTime.Hour;
210 minutePicker.CurrentValue = currentTime.Minute;
215 /// The is24hourview value of TimePicker.
217 /// <since_tizen> 9 </since_tizen>
218 public bool Is24HourView
222 return (bool)GetValue(Is24HourViewProperty);
226 SetValue(Is24HourViewProperty, value);
227 NotifyPropertyChanged();
230 private bool InternalIs24HourView
238 if (is24HourView == value) return;
240 Console.WriteLine(" Is 24 Hour View");
241 is24HourView = value;
245 hourPicker.MinValue = 0;
246 hourPicker.MaxValue = 23;
247 hourPicker.CurrentValue = currentTime.Hour;
251 hourPicker.MinValue = 1;
252 hourPicker.MaxValue = 12;
253 PickersOrderSet(true);
255 if (currentTime.Hour > 12)
257 ampmPicker.CurrentValue = 2;
258 hourPicker.CurrentValue = currentTime.Hour - 12;
265 /// Initialize TimePicker object.
267 [EditorBrowsable(EditorBrowsableState.Never)]
268 public override void OnInitialize()
271 SetAccessibilityConstructor(Role.DateEditor);
273 hourPicker = new Picker()
279 hourPicker.ValueChanged += OnHourValueChanged;
281 minutePicker = new Picker()
287 minutePicker.ValueChanged += OnMinuteValueChanged;
289 ampmPicker = new Picker()
295 ampmPicker.ValueChanged += OnAmpmValueChanged;
297 currentTime = DateTime.Now;
298 if (currentTime.Hour > 12)
300 ampmPicker.CurrentValue = 2;
301 hourPicker.CurrentValue = currentTime.Hour - 12;
305 ampmPicker.CurrentValue = 1;
306 hourPicker.CurrentValue = currentTime.Hour;
309 minutePicker.CurrentValue = currentTime.Minute;
315 /// Applies style to TimePicker.
317 /// <param name="viewStyle">The style to apply.</param>
318 [EditorBrowsable(EditorBrowsableState.Never)]
319 public override void ApplyStyle(ViewStyle viewStyle)
321 base.ApplyStyle(viewStyle);
323 var timePickerStyle = viewStyle as TimePickerStyle;
325 if (timePickerStyle == null) return;
328 if (timePickerStyle?.CellPadding != null && Layout != null)
329 ((LinearLayout)Layout).CellPadding = new Size2D(timePickerStyle.CellPadding.Width, timePickerStyle.CellPadding.Height);
331 //Apply Internal Pickers style.
332 if (timePickerStyle?.Pickers != null && hourPicker != null && minutePicker != null && ampmPicker != null)
334 hourPicker.ApplyStyle(timePickerStyle.Pickers);
335 minutePicker.ApplyStyle(timePickerStyle.Pickers);
336 ampmPicker.ApplyStyle(timePickerStyle.Pickers);
341 /// ToDo : only key navigation is enabled, and value editing is added as an very simple operation. by toggling enter key, it switches edit mode.
342 /// ToDo : this should be fixed and changed properly by owner. (And UX SPEC should be referenced also)
344 /// <param name="currentFocusedView"></param>
345 /// <param name="direction"></param>
346 /// <param name="loopEnabled"></param>
347 /// <returns></returns>
348 [EditorBrowsable(EditorBrowsableState.Never)]
349 public override View GetNextFocusableView(View currentFocusedView, View.FocusDirection direction, bool loopEnabled)
351 if (currentFocusedView == hourPicker)
353 if (direction == View.FocusDirection.Right)
359 else if (currentFocusedView == minutePicker)
361 if (direction == View.FocusDirection.Right)
365 else if (direction == View.FocusDirection.Left)
370 else if (currentFocusedView == ampmPicker)
372 if (direction == View.FocusDirection.Left)
380 [SuppressMessage("Microsoft.Reliability",
381 "CA2000:DisposeObjectsBeforeLosingScope",
382 Justification = "The CellPadding will be dispose when the time picker disposed")]
383 private void Initialize()
385 HeightSpecification = LayoutParamPolicies.MatchParent;
387 Layout = new LinearLayout()
389 LinearOrientation = LinearLayout.Orientation.Horizontal,
391 Console.WriteLine("initialize");
393 is24HourView = false;
395 PickersOrderSet(false);
399 private void ChangeTime(int hour, int minute, bool hourUpdate)
402 currentTime = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, hour, currentTime.Minute, 0);
404 currentTime = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, currentTime.Hour, minute, 0);
407 private void OnHourValueChanged(object sender, ValueChangedEventArgs e)
409 if (currentTime.Hour == e.Value) return;
415 if (e.Value == 12) ChangeTime(0, 0, true);
416 else ChangeTime(e.Value, 0, true);
420 if (e.Value == 12) ChangeTime(12, 0, true);
421 else ChangeTime(e.Value + 12, 0, true);
425 ChangeTime(e.Value, 0, true);
430 private void OnMinuteValueChanged(object sender, ValueChangedEventArgs e)
432 if (currentTime.Minute == e.Value) return;
434 ChangeTime(0, e.Value, false);
439 private void OnAmpmValueChanged(object sender, ValueChangedEventArgs e)
441 if ((isAm && e.Value == 1) || (!isAm && e.Value == 2)) return;
445 if (currentTime.Hour == 12) ChangeTime(0, 0, true);
446 else ChangeTime(currentTime.Hour - 12, 0, true);
452 if (currentTime.Hour == 0) ChangeTime(12, 0, true);
453 else ChangeTime(currentTime.Hour + 12, 0, true);
461 private void OnTimeChanged()
463 TimeChangedEventArgs eventArgs = new TimeChangedEventArgs(currentTime);
464 TimeChanged?.Invoke(this, eventArgs);
467 private void PickersOrderSet(bool ampmForceSet)
469 //FIXME: Check the pickers located in already proper position or not.
471 Remove(minutePicker);
474 //Get current system locale's time pattern
475 DateTimeFormatInfo timeFormatInfo = CultureInfo.CurrentCulture.DateTimeFormat;
476 String timePattern = timeFormatInfo.ShortTimePattern;
477 String[] timePatternArray = timePattern.Split(' ', ':');
479 foreach (String format in timePatternArray)
481 if (format.IndexOf("H") != -1 || format.IndexOf("h") != -1) Add(hourPicker);
482 else if (format.IndexOf("M") != -1 || format.IndexOf("m") != -1) Add(minutePicker);
483 else if (format.IndexOf("t") != -1)
485 is24HourView = false;
486 ampmForceSet = false;
491 if (ampmForceSet) Add(ampmPicker);
494 private void SetAmpmText()
496 //FIXME: There is no localeChanged Event for Component now
497 // AMPM text has to update when system locale changed.
498 CultureInfo info = CultureInfo.CurrentCulture;
499 ampmText = new string[] { info.DateTimeFormat.AMDesignator, info.DateTimeFormat.PMDesignator };
500 ampmPicker.DisplayedValues = new ReadOnlyCollection<string>(ampmText);