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 is24HourView = value;
244 hourPicker.MinValue = 0;
245 hourPicker.MaxValue = 23;
246 hourPicker.CurrentValue = currentTime.Hour;
250 hourPicker.MinValue = 1;
251 hourPicker.MaxValue = 12;
252 PickersOrderSet(true);
254 if (currentTime.Hour > 12)
256 ampmPicker.CurrentValue = 2;
257 hourPicker.CurrentValue = currentTime.Hour - 12;
265 [EditorBrowsable(EditorBrowsableState.Never)]
266 protected override void OnEnabled(bool enabled)
268 base.OnEnabled(enabled);
270 hourPicker.IsEnabled = enabled;
271 minutePicker.IsEnabled = enabled;
272 ampmPicker.IsEnabled = enabled;
276 /// Initialize TimePicker object.
278 [EditorBrowsable(EditorBrowsableState.Never)]
279 public override void OnInitialize()
282 AccessibilityRole = Role.DateEditor;
284 hourPicker = new Picker()
290 hourPicker.ValueChanged += OnHourValueChanged;
292 minutePicker = new Picker()
298 minutePicker.ValueChanged += OnMinuteValueChanged;
300 ampmPicker = new Picker()
306 ampmPicker.ValueChanged += OnAmpmValueChanged;
308 currentTime = DateTime.Now;
309 if (currentTime.Hour > 12)
311 ampmPicker.CurrentValue = 2;
312 hourPicker.CurrentValue = currentTime.Hour - 12;
316 ampmPicker.CurrentValue = 1;
317 hourPicker.CurrentValue = currentTime.Hour;
320 minutePicker.CurrentValue = currentTime.Minute;
326 /// Applies style to TimePicker.
328 /// <param name="viewStyle">The style to apply.</param>
329 [EditorBrowsable(EditorBrowsableState.Never)]
330 public override void ApplyStyle(ViewStyle viewStyle)
332 base.ApplyStyle(viewStyle);
334 var timePickerStyle = viewStyle as TimePickerStyle;
336 if (timePickerStyle == null) return;
339 if (timePickerStyle?.CellPadding != null && Layout != null)
340 ((LinearLayout)Layout).CellPadding = new Size2D(timePickerStyle.CellPadding.Width, timePickerStyle.CellPadding.Height);
342 //Apply Internal Pickers style.
343 if (timePickerStyle?.Pickers != null && hourPicker != null && minutePicker != null && ampmPicker != null)
345 hourPicker.ApplyStyle(timePickerStyle.Pickers);
346 minutePicker.ApplyStyle(timePickerStyle.Pickers);
347 ampmPicker.ApplyStyle(timePickerStyle.Pickers);
352 /// ToDo : only key navigation is enabled, and value editing is added as an very simple operation. by toggling enter key, it switches edit mode.
353 /// ToDo : this should be fixed and changed properly by owner. (And UX SPEC should be referenced also)
355 /// <param name="currentFocusedView"></param>
356 /// <param name="direction"></param>
357 /// <param name="loopEnabled"></param>
358 /// <returns></returns>
359 [EditorBrowsable(EditorBrowsableState.Never)]
360 public override View GetNextFocusableView(View currentFocusedView, View.FocusDirection direction, bool loopEnabled)
362 if (currentFocusedView == hourPicker)
364 if (direction == View.FocusDirection.Right)
370 else if (currentFocusedView == minutePicker)
372 if (direction == View.FocusDirection.Right)
376 else if (direction == View.FocusDirection.Left)
381 else if (currentFocusedView == ampmPicker)
383 if (direction == View.FocusDirection.Left)
391 [SuppressMessage("Microsoft.Reliability",
392 "CA2000:DisposeObjectsBeforeLosingScope",
393 Justification = "The CellPadding will be dispose when the time picker disposed")]
394 private void Initialize()
396 Layout = new LinearLayout()
398 LinearOrientation = LinearLayout.Orientation.Horizontal,
401 is24HourView = false;
403 PickersOrderSet(false);
407 private void ChangeTime(int hour, int minute, bool hourUpdate)
410 currentTime = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, hour, currentTime.Minute, 0);
412 currentTime = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, currentTime.Hour, minute, 0);
415 private void OnHourValueChanged(object sender, ValueChangedEventArgs e)
417 if (currentTime.Hour == e.Value) return;
423 if (e.Value == 12) ChangeTime(0, 0, true);
424 else ChangeTime(e.Value, 0, true);
428 if (e.Value == 12) ChangeTime(12, 0, true);
429 else ChangeTime(e.Value + 12, 0, true);
433 ChangeTime(e.Value, 0, true);
438 private void OnMinuteValueChanged(object sender, ValueChangedEventArgs e)
440 if (currentTime.Minute == e.Value) return;
442 ChangeTime(0, e.Value, false);
447 private void OnAmpmValueChanged(object sender, ValueChangedEventArgs e)
449 if ((isAm && e.Value == 1) || (!isAm && e.Value == 2)) return;
453 if (currentTime.Hour == 12) ChangeTime(0, 0, true);
454 else ChangeTime(currentTime.Hour - 12, 0, true);
460 if (currentTime.Hour == 0) ChangeTime(12, 0, true);
461 else ChangeTime(currentTime.Hour + 12, 0, true);
469 private void OnTimeChanged()
471 TimeChangedEventArgs eventArgs = new TimeChangedEventArgs(currentTime);
472 TimeChanged?.Invoke(this, eventArgs);
475 private void PickersOrderSet(bool ampmForceSet)
477 //FIXME: Check the pickers located in already proper position or not.
479 Remove(minutePicker);
482 //Get current system locale's time pattern
483 DateTimeFormatInfo timeFormatInfo = CultureInfo.CurrentCulture.DateTimeFormat;
484 String timePattern = timeFormatInfo.ShortTimePattern;
485 String[] timePatternArray = timePattern.Split(' ', ':');
487 foreach (String format in timePatternArray)
489 if (format.IndexOf("H") != -1 || format.IndexOf("h") != -1) Add(hourPicker);
490 else if (format.IndexOf("M") != -1 || format.IndexOf("m") != -1) Add(minutePicker);
491 else if (format.IndexOf("t") != -1)
493 is24HourView = false;
494 ampmForceSet = false;
499 if (ampmForceSet) Add(ampmPicker);
502 private void SetAmpmText()
504 //FIXME: There is no localeChanged Event for Component now
505 // AMPM text has to update when system locale changed.
506 CultureInfo info = CultureInfo.CurrentCulture;
507 ampmText = new string[] { info.DateTimeFormat.AMDesignator, info.DateTimeFormat.PMDesignator };
508 ampmPicker.DisplayedValues = new ReadOnlyCollection<string>(ampmText);