[NUI] Fix picker not to use ViewStyle. (#3267)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / TimePicker.cs
1 /* Copyright (c) 2021 Samsung Electronics Co., Ltd.
2  *
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
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
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.
14  *
15  */
16 using System;
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
24 namespace Tizen.NUI.Components
25 {
26     /// <summary>
27     /// TimeChangedEventArgs is a class to notify changed TimePicker value argument which will sent to user.
28     /// </summary>
29     [EditorBrowsable(EditorBrowsableState.Never)]
30     public class TimeChangedEventArgs : EventArgs
31     {
32         /// <summary>
33         /// TimeChangedEventArgs default constructor.
34         /// <param name="time">time value of TimePicker.</param>
35         /// </summary>
36         [EditorBrowsable(EditorBrowsableState.Never)]   
37         public TimeChangedEventArgs(DateTime time)
38         {
39             Time = time;
40         }
41
42         /// <summary>
43         /// TimeChangedEventArgs default constructor.
44         /// <returns>The current time value of TimePicker.</returns>
45         /// </summary>
46         [EditorBrowsable(EditorBrowsableState.Never)]   
47         public DateTime Time { get; }
48     }
49
50     /// <summary>
51     /// TimePicker is a class which provides a function that allows the user to select 
52     /// a time through a scrolling motion by expressing the specified value as a list.
53     /// TimePicker expresses the current time using the locale information of the system.
54     /// </summary>
55     [EditorBrowsable(EditorBrowsableState.Never)]
56     public class TimePicker : Control
57     {
58         private bool isAm;
59         private bool is24HourView;
60         private DateTime currentTime;
61         private String[] ampmText;
62         private Picker hourPicker;
63         private Picker minutePicker;
64         private Picker ampmPicker;
65
66         /// <summary>
67         /// Creates a new instance of TimePicker.
68         /// </summary>
69         [EditorBrowsable(EditorBrowsableState.Never)]
70         public TimePicker()
71         {
72         }
73
74         /// <summary>
75         /// Creates a new instance of TimePicker.
76         /// </summary>
77         /// <param name="style">Creates TimePicker by special style defined in UX.</param>
78         [EditorBrowsable(EditorBrowsableState.Never)]
79         public TimePicker(string style) : base(style)
80         {
81         }
82
83         /// <summary>
84         /// Creates a new instance of TimePicker.
85         /// </summary>
86         /// <param name="timePickerStyle">Creates TimePicker by style customized by user.</param>
87         [EditorBrowsable(EditorBrowsableState.Never)]
88         public TimePicker(TimePickerStyle timePickerStyle) : base(timePickerStyle)
89         {
90         }
91
92         /// <summary>
93         /// Dispose TimePicker and all children on it.
94         /// </summary>
95         /// <param name="type">Dispose type.</param>
96         [EditorBrowsable(EditorBrowsableState.Never)]
97         protected override void Dispose(DisposeTypes type)
98         {
99             if (disposed)
100             {
101                 return;
102             }
103
104             if (type == DisposeTypes.Explicit)
105             {
106                 Remove(hourPicker);
107                 Utility.Dispose(hourPicker);
108                 hourPicker = null;
109                 Remove(minutePicker);
110                 Utility.Dispose(minutePicker);
111                 minutePicker = null;
112                 Remove(ampmPicker);
113                 Utility.Dispose(ampmPicker);
114                 ampmPicker = null;
115             }
116
117             base.Dispose(type);
118         }
119
120         /// <summary>
121         /// An event emitted when TimePicker value changed, user can subscribe or unsubscribe to this event handler.
122         /// </summary>
123         [EditorBrowsable(EditorBrowsableState.Never)]
124         public event EventHandler<TimeChangedEventArgs> TimeChanged;
125
126         /// <summary>
127         /// The hour value of TimePicker.
128         /// </summary>
129         [EditorBrowsable(EditorBrowsableState.Never)]
130         public DateTime Time
131         {
132             get
133             {
134                 return currentTime;
135             }
136             set
137             {
138                 currentTime = value;
139                 if (!is24HourView)
140                 {
141                     if (currentTime.Hour >= 12 && currentTime.Hour <= 23)
142                     {
143                         isAm = false;
144                         if (currentTime.Hour == 12) hourPicker.CurrentValue = currentTime.Hour;
145                         else hourPicker.CurrentValue = currentTime.Hour - 12;
146                         ampmPicker.CurrentValue = 2;
147                     }
148                     else 
149                     {
150                         isAm = true;
151                         hourPicker.CurrentValue = currentTime.Hour;
152                         ampmPicker.CurrentValue = 1;
153                     }
154                 }
155                 else hourPicker.CurrentValue = currentTime.Hour;
156
157                 minutePicker.CurrentValue = currentTime.Minute;
158             }
159         }
160
161         /// <summary>
162         /// The is24hourview value of TimePicker.
163         /// </summary>
164         [EditorBrowsable(EditorBrowsableState.Never)]
165         public bool Is24HourView
166         {
167             get
168             {
169                 return is24HourView;
170             }
171             set
172             {
173                 if (is24HourView == value) return;
174
175                 Console.WriteLine(" Is 24 Hour View");
176                 is24HourView = value;
177                 if (value == true)
178                 {
179                     Remove(ampmPicker);
180                     hourPicker.MinValue = 0;
181                     hourPicker.MaxValue = 23;
182                     hourPicker.CurrentValue = currentTime.Hour;
183                 }
184                 else 
185                 {
186                     hourPicker.MinValue = 1;
187                     hourPicker.MaxValue = 12;
188                     PickersOrderSet(true);
189                     SetAmpmText();
190                     if (currentTime.Hour > 12)
191                     {
192                         ampmPicker.CurrentValue = 2;
193                         hourPicker.CurrentValue = currentTime.Hour - 12;
194                     }
195                 }
196             }
197         }
198
199         /// <summary>
200         /// Initialize TimePicker object.
201         /// </summary>
202         [EditorBrowsable(EditorBrowsableState.Never)]
203         public override void OnInitialize()
204         {
205             base.OnInitialize();
206             SetAccessibilityConstructor(Role.DateEditor);
207
208             hourPicker = new Picker()
209             {
210                 MinValue = 1,
211                 MaxValue = 12,
212             };
213             hourPicker.ValueChanged += OnHourValueChanged;
214
215             minutePicker = new Picker()
216             {
217                 MinValue = 0,
218                 MaxValue = 59,
219             };
220             minutePicker.ValueChanged += OnMinuteValueChanged;
221
222             ampmPicker = new Picker()
223             {
224                 MinValue = 1,
225                 MaxValue = 2,
226             };
227             ampmPicker.ValueChanged += OnAmpmValueChanged;
228
229             currentTime = DateTime.Now;
230             Console.WriteLine(" Time " + currentTime.Hour + " " + currentTime.Minute);
231             if (currentTime.Hour > 12)
232             {
233                 ampmPicker.CurrentValue = 2;
234                 hourPicker.CurrentValue = currentTime.Hour - 12;
235             }
236             else
237                 hourPicker.CurrentValue = currentTime.Hour;
238
239             minutePicker.CurrentValue = currentTime.Minute;
240
241             Initialize();
242         }
243
244         /// <summary>
245         /// Applies style to TimePicker.
246         /// </summary>
247         /// <param name="viewStyle">The style to apply.</param>
248         [EditorBrowsable(EditorBrowsableState.Never)]
249         public override void ApplyStyle(ViewStyle viewStyle)
250         {
251             base.ApplyStyle(viewStyle);
252
253             var timePickerStyle = viewStyle as TimePickerStyle;
254
255             if (timePickerStyle == null) return;
256
257             //Apply CellPadding.
258             if (timePickerStyle?.CellPadding != null && Layout != null)
259                 ((LinearLayout)Layout).CellPadding = new Size2D(timePickerStyle.CellPadding.Width, timePickerStyle.CellPadding.Height);
260             
261             //Apply Internal Pickers style.
262             if (timePickerStyle?.Pickers != null && hourPicker != null && minutePicker != null && ampmPicker != null)
263             {
264                 hourPicker.ApplyStyle(timePickerStyle.Pickers);
265                 minutePicker.ApplyStyle(timePickerStyle.Pickers);
266                 ampmPicker.ApplyStyle(timePickerStyle.Pickers);
267             }
268         }
269                 
270         [SuppressMessage("Microsoft.Reliability",
271                          "CA2000:DisposeObjectsBeforeLosingScope",
272                          Justification = "The CellPadding will be dispose when the time picker disposed")]
273         private void Initialize()
274         {
275             HeightSpecification = LayoutParamPolicies.MatchParent;
276
277             Layout = new LinearLayout() { 
278                 LinearOrientation = LinearLayout.Orientation.Horizontal,
279             };
280             Console.WriteLine("initialize");
281
282             is24HourView = false;
283
284             PickersOrderSet(false);
285             SetAmpmText();
286         }
287
288         private void ChangeTime(int hour, int minute, bool hourUpdate)
289         {
290             if (hourUpdate)
291                 currentTime = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, hour, currentTime.Minute, 0);
292             else
293                 currentTime = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, currentTime.Hour, minute, 0);
294         }
295
296         private void OnHourValueChanged(object sender, ValueChangedEventArgs e)
297         {
298             if (currentTime.Hour == e.Value) return;
299
300             if (!is24HourView)
301             {
302                 if (isAm) 
303                 {
304                     if (e.Value == 12) ChangeTime(12, 0, true);
305                     else ChangeTime(e.Value, 0, true);
306                 }
307                 else 
308                 {
309                     if (e.Value == 12) ChangeTime(0, 0, true);
310                     else ChangeTime(e.Value + 12, 0, true);
311                 }
312             }
313             else
314                 ChangeTime(e.Value, 0, true);
315             
316             OnTimeChanged();
317         }
318
319         private void OnMinuteValueChanged(object sender, ValueChangedEventArgs e)
320         { 
321             if (currentTime.Minute == e.Value) return;
322
323             ChangeTime(0, e.Value, false);
324
325             OnTimeChanged();
326         }
327
328         private void OnAmpmValueChanged(object sender, ValueChangedEventArgs e)
329         { 
330             if ((isAm && e.Value == 1) || (!isAm && e.Value == 2)) return;
331
332             if (e.Value == 1)
333             { //AM
334                 if (currentTime.Hour > 12 || currentTime.Hour == 0)
335                 { 
336                     if (currentTime.Hour == 0) ChangeTime(12, 0, true);
337                     else ChangeTime(currentTime.Hour - 12, 0, true);
338                 }
339                 isAm = true;
340             }
341             else 
342             { //PM
343                 if (currentTime.Hour > 0 && currentTime.Hour <= 12)
344                 {
345                      if (currentTime.Hour == 12) ChangeTime(0, 0, true);
346                      else ChangeTime(currentTime.Hour + 12, 0, true);
347                 }
348                 isAm = false;
349             }
350
351             OnTimeChanged();
352         }
353
354         private void OnTimeChanged()
355         { 
356             TimeChangedEventArgs eventArgs = new TimeChangedEventArgs(currentTime);
357             TimeChanged?.Invoke(this, eventArgs);
358         }
359
360         private void PickersOrderSet(bool ampmForceSet)
361         {
362             //FIXME: Check the pickers located in already proper position or not.
363             Remove(hourPicker);
364             Remove(minutePicker);
365             Remove(ampmPicker);
366
367             //Get current system locale's time pattern
368             String locale = Environment.GetEnvironmentVariable("LC_TIME");
369             DateTimeFormatInfo timeFormatInfo = new CultureInfo(locale, false ).DateTimeFormat;
370             String timePattern = timeFormatInfo.ShortTimePattern;
371             String[] timePatternArray = timePattern.Split(' ', ':');
372
373             foreach (String format in timePatternArray) {
374                 if (format.IndexOf("H") != -1|| format.IndexOf("h") != -1)  Add(hourPicker);
375                 else if (format.IndexOf("M") != -1 || format.IndexOf("m") != -1) Add(minutePicker);
376                 else if (format.IndexOf("t") != -1) 
377                 {
378                     is24HourView = false;
379                     ampmForceSet = false;
380                     Add(ampmPicker);
381                 }
382             }
383
384             if (ampmForceSet) Add(ampmPicker);
385         }
386
387         private void SetAmpmText()
388         {
389             //FIXME: There is no localeChanged Event for Component now
390             //       AMPM text has to update when system locale changed.
391             String locale = Environment.GetEnvironmentVariable("LC_TIME");
392             CultureInfo info = new CultureInfo(locale);
393             ampmText = new string[] {info.DateTimeFormat.AMDesignator, info.DateTimeFormat.PMDesignator};
394             ampmPicker.DisplayedValues = new ReadOnlyCollection<string>(ampmText);
395         }
396     }
397 }