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.
18 using Tizen.NUI.BaseComponents;
19 using System.Collections.Generic;
20 using System.Collections.ObjectModel;
21 using System.ComponentModel;
22 using System.Globalization;
23 using System.Diagnostics.CodeAnalysis;
24 using Tizen.NUI.Binding;
26 namespace Tizen.NUI.Components
29 /// DateChangedEventArgs is a class to notify changed DatePicker value argument which will sent to user.
31 /// <since_tizen> 9 </since_tizen>
32 public class DateChangedEventArgs : EventArgs
35 /// DateChangedEventArgs default constructor.
36 /// <param name="date">date value of DatePicker.</param>
38 [EditorBrowsable(EditorBrowsableState.Never)]
39 public DateChangedEventArgs(DateTime date)
45 /// DateChangedEventArgs default constructor.
46 /// <returns>The current date value of DatePicker.</returns>
48 /// <since_tizen> 9 </since_tizen>
49 public DateTime Date { get; }
53 /// DatePicker is a class which provides a function that allows the user to select
54 /// a date through a scrolling motion by expressing the specified value as a list.
55 /// DatePicker expresses the current date using the locale information of the system.
56 /// Year range is 1970~2038 (glibc time_t struct min, max value)
58 /// <since_tizen> 9 </since_tizen>
59 public class DatePicker : Control
64 [EditorBrowsable(EditorBrowsableState.Never)]
65 public static readonly BindableProperty DateProperty = BindableProperty.Create(nameof(Date), typeof(DateTime), typeof(DatePicker), default(DateTime), propertyChanged: (bindable, oldValue, newValue) =>
67 var instance = (DatePicker)bindable;
70 instance.InternalDate = (DateTime)newValue;
73 defaultValueCreator: (bindable) =>
75 var instance = (DatePicker)bindable;
76 return instance.InternalDate;
79 private DateTime currentDate;
80 private Picker dayPicker;
81 private Picker monthPicker;
82 private Picker yearPicker;
85 /// Creates a new instance of DatePicker.
87 /// <since_tizen> 9 </since_tizen>
90 SetKeyboardNavigationSupport(true);
94 /// Creates a new instance of DatePicker.
96 /// <param name="style">Creates DatePicker by special style defined in UX.</param>
97 /// <since_tizen> 9 </since_tizen>
98 public DatePicker(string style) : base(style)
100 SetKeyboardNavigationSupport(true);
104 /// Creates a new instance of DatePicker.
106 /// <param name="datePickerStyle">Creates DatePicker by style customized by user.</param>
107 /// <since_tizen> 9 </since_tizen>
108 public DatePicker(DatePickerStyle datePickerStyle) : base(datePickerStyle)
110 SetKeyboardNavigationSupport(true);
114 [EditorBrowsable(EditorBrowsableState.Never)]
115 protected override void OnEnabled(bool enabled)
117 base.OnEnabled(enabled);
119 dayPicker.IsEnabled = enabled;
120 monthPicker.IsEnabled = enabled;
121 yearPicker.IsEnabled = enabled;
125 /// Dispose DatePicker and all children on it.
127 /// <param name="type">Dispose type.</param>
128 [EditorBrowsable(EditorBrowsableState.Never)]
129 protected override void Dispose(DisposeTypes type)
136 if (type == DisposeTypes.Explicit)
139 Utility.Dispose(monthPicker);
142 Utility.Dispose(dayPicker);
145 Utility.Dispose(yearPicker);
153 /// An event emitted when DatePicker value changed, user can subscribe or unsubscribe to this event handler.
155 /// <since_tizen> 9 </since_tizen>
156 public event EventHandler<DateChangedEventArgs> DateChanged;
159 /// The Date value of DatePicker.
161 /// <since_tizen> 9 </since_tizen>
166 return (DateTime)GetValue(DateProperty);
170 SetValue(DateProperty, value);
171 NotifyPropertyChanged();
174 private DateTime InternalDate
183 dayPicker.CurrentValue = currentDate.Day;
184 monthPicker.CurrentValue = currentDate.Month;
185 yearPicker.CurrentValue = currentDate.Year;
190 /// Initialize TimePicker object.
192 [EditorBrowsable(EditorBrowsableState.Never)]
193 public override void OnInitialize()
196 AccessibilityRole = Role.DateEditor;
198 dayPicker = new Picker()
204 dayPicker.ValueChanged += OnDayValueChanged;
206 monthPicker = new Picker()
212 monthPicker.ValueChanged += OnMonthValueChanged;
214 yearPicker = new Picker()
220 yearPicker.ValueChanged += OnYearValueChanged;
222 currentDate = DateTime.Now;
223 dayPicker.CurrentValue = currentDate.Day;
224 monthPicker.CurrentValue = currentDate.Month;
225 yearPicker.CurrentValue = currentDate.Year;
231 [EditorBrowsable(EditorBrowsableState.Never)]
232 [SuppressMessage("Microsoft.Reliability",
233 "CA2000:DisposeObjectsBeforeLosingScope",
234 Justification = "The CellPadding will be dispose when the date picker disposed")]
235 public override void ApplyStyle(ViewStyle viewStyle)
237 base.ApplyStyle(viewStyle);
239 if (viewStyle is DatePickerStyle datePickerStyle && Layout is LinearLayout linearLayout)
241 linearLayout.CellPadding = new Size(datePickerStyle.CellPadding.Width, datePickerStyle.CellPadding.Height);
243 yearPicker.ApplyStyle(datePickerStyle.Pickers);
244 monthPicker.ApplyStyle(datePickerStyle.Pickers);
245 dayPicker.ApplyStyle(datePickerStyle.Pickers);
250 /// ToDo : only key navigation is enabled, and value editing is added as an very simple operation. by toggling enter key, it switches edit mode.
251 /// ToDo : this should be fixed and changed properly by owner. (And UX SPEC should be referenced also)
253 /// <param name="currentFocusedView"></param>
254 /// <param name="direction"></param>
255 /// <param name="loopEnabled"></param>
256 /// <returns></returns>
257 [EditorBrowsable(EditorBrowsableState.Never)]
258 public override View GetNextFocusableView(View currentFocusedView, View.FocusDirection direction, bool loopEnabled)
260 if (currentFocusedView == yearPicker)
262 if (direction == View.FocusDirection.Right)
267 else if (currentFocusedView == monthPicker)
269 if (direction == View.FocusDirection.Right)
273 else if (direction == View.FocusDirection.Left)
278 else if (currentFocusedView == dayPicker)
280 if (direction == View.FocusDirection.Left)
288 private void Initialize()
290 HeightSpecification = LayoutParamPolicies.MatchParent;
292 Layout = new LinearLayout()
294 LinearOrientation = LinearLayout.Orientation.Horizontal,
299 MaxDaySet(currentDate.Year, currentDate.Month);
302 private void OnDayValueChanged(object sender, ValueChangedEventArgs e)
304 if (currentDate.Day == e.Value) return;
306 currentDate = new DateTime(currentDate.Year, currentDate.Month, e.Value);
311 private void OnMonthValueChanged(object sender, ValueChangedEventArgs e)
313 if (currentDate.Month == e.Value) return;
315 MaxDaySet(currentDate.Year, e.Value);
320 private void OnYearValueChanged(object sender, ValueChangedEventArgs e)
322 if (currentDate.Year == e.Value) return;
324 MaxDaySet(e.Value, currentDate.Month);
329 private void OnDateChanged()
331 DateChangedEventArgs eventArgs = new DateChangedEventArgs(currentDate);
332 DateChanged?.Invoke(this, eventArgs);
335 private void MaxDaySet(int year, int month)
337 int maxDaysInMonth = DateTime.DaysInMonth(year, month);
338 dayPicker.MaxValue = maxDaysInMonth;
339 if (currentDate.Day > maxDaysInMonth)
341 currentDate = new DateTime(year, month, maxDaysInMonth);
342 dayPicker.CurrentValue = maxDaysInMonth;
345 currentDate = new DateTime(year, month, currentDate.Day);
348 //FIXME: There is no way to know when system locale changed in NUI.
349 // Pickers order and Month text has to be follow system locale.
350 private void PickersOrderSet()
352 DateTimeFormatInfo DateFormat = CultureInfo.CurrentCulture.DateTimeFormat;
353 String temp = DateFormat.ShortDatePattern;
354 String[] strArray = temp.Split(' ', '/');
355 foreach (String format in strArray)
357 if (format.IndexOf("M") != -1 || format.IndexOf("m") != -1) Add(monthPicker);
358 else if (format.IndexOf("d") != -1 || format.IndexOf("D") != -1) Add(dayPicker);
359 else if (format.IndexOf("y") != -1 || format.IndexOf("Y") != -1) Add(yearPicker);
363 private void SetMonthText()
365 CultureInfo info = CultureInfo.CurrentCulture;
366 monthPicker.DisplayedValues = new ReadOnlyCollection<string>(info.DateTimeFormat.AbbreviatedMonthNames);