/* Copyright (c) 2021 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using Tizen.NUI.BaseComponents;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using Tizen.NUI.Binding;
namespace Tizen.NUI.Components
{
///
/// TimeChangedEventArgs is a class to notify changed TimePicker value argument which will sent to user.
///
/// 9
public class TimeChangedEventArgs : EventArgs
{
///
/// TimeChangedEventArgs default constructor.
/// time value of TimePicker.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public TimeChangedEventArgs(DateTime time)
{
Time = time;
}
///
/// TimeChangedEventArgs default constructor.
/// The current time value of TimePicker.
///
/// 9
public DateTime Time { get; }
}
///
/// TimePicker is a class which provides a function that allows the user to select
/// a time through a scrolling motion by expressing the specified value as a list.
/// TimePicker expresses the current time using the locale information of the system.
///
/// 9
public class TimePicker : Control
{
///
/// TimeProperty
///
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly BindableProperty TimeProperty = BindableProperty.Create(nameof(Time), typeof(DateTime), typeof(TimePicker), default(DateTime), propertyChanged: (bindable, oldValue, newValue) =>
{
var instance = (TimePicker)bindable;
if (newValue != null)
{
instance.InternalTime = (DateTime)newValue;
}
},
defaultValueCreator: (bindable) =>
{
var instance = (TimePicker)bindable;
return instance.InternalTime;
});
///
/// Is24HourViewProperty
///
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly BindableProperty Is24HourViewProperty = BindableProperty.Create(nameof(Is24HourView), typeof(bool), typeof(TimePicker), default(bool), propertyChanged: (bindable, oldValue, newValue) =>
{
var instance = (TimePicker)bindable;
if (newValue != null)
{
instance.InternalIs24HourView = (bool)newValue;
}
},
defaultValueCreator: (bindable) =>
{
var instance = (TimePicker)bindable;
return instance.InternalIs24HourView;
});
private bool isAm;
private bool is24HourView;
private DateTime currentTime;
private String[] ampmText;
private Picker hourPicker;
private Picker minutePicker;
private Picker ampmPicker;
///
/// Creates a new instance of TimePicker.
///
/// 9
public TimePicker()
{
}
///
/// Creates a new instance of TimePicker.
///
/// Creates TimePicker by special style defined in UX.
/// 9
public TimePicker(string style) : base(style)
{
}
///
/// Creates a new instance of TimePicker.
///
/// Creates TimePicker by style customized by user.
/// 9
public TimePicker(TimePickerStyle timePickerStyle) : base(timePickerStyle)
{
}
///
/// Dispose TimePicker and all children on it.
///
/// Dispose type.
[EditorBrowsable(EditorBrowsableState.Never)]
protected override void Dispose(DisposeTypes type)
{
if (disposed)
{
return;
}
if (type == DisposeTypes.Explicit)
{
Remove(hourPicker);
Utility.Dispose(hourPicker);
hourPicker = null;
Remove(minutePicker);
Utility.Dispose(minutePicker);
minutePicker = null;
Remove(ampmPicker);
Utility.Dispose(ampmPicker);
ampmPicker = null;
}
base.Dispose(type);
}
///
/// An event emitted when TimePicker value changed, user can subscribe or unsubscribe to this event handler.
///
/// 9
public event EventHandler TimeChanged;
///
/// The hour value of TimePicker.
///
/// 9
public DateTime Time
{
get
{
return (DateTime)GetValue(TimeProperty);
}
set
{
SetValue(TimeProperty, value);
NotifyPropertyChanged();
}
}
private DateTime InternalTime
{
get
{
return currentTime;
}
set
{
currentTime = value;
if (!is24HourView)
{
if (currentTime.Hour >= 12 && currentTime.Hour <= 23)
{
isAm = false;
if (currentTime.Hour == 12) hourPicker.CurrentValue = currentTime.Hour;
else hourPicker.CurrentValue = currentTime.Hour - 12;
ampmPicker.CurrentValue = 2;
}
else
{
isAm = true;
if (currentTime.Hour == 0) hourPicker.CurrentValue = 12;
else hourPicker.CurrentValue = currentTime.Hour;
ampmPicker.CurrentValue = 1;
}
}
else hourPicker.CurrentValue = currentTime.Hour;
minutePicker.CurrentValue = currentTime.Minute;
}
}
///
/// The is24hourview value of TimePicker.
///
/// 9
public bool Is24HourView
{
get
{
return (bool)GetValue(Is24HourViewProperty);
}
set
{
SetValue(Is24HourViewProperty, value);
NotifyPropertyChanged();
}
}
private bool InternalIs24HourView
{
get
{
return is24HourView;
}
set
{
if (is24HourView == value) return;
Console.WriteLine(" Is 24 Hour View");
is24HourView = value;
if (value == true)
{
Remove(ampmPicker);
hourPicker.MinValue = 0;
hourPicker.MaxValue = 23;
hourPicker.CurrentValue = currentTime.Hour;
}
else
{
hourPicker.MinValue = 1;
hourPicker.MaxValue = 12;
PickersOrderSet(true);
SetAmpmText();
if (currentTime.Hour > 12)
{
ampmPicker.CurrentValue = 2;
hourPicker.CurrentValue = currentTime.Hour - 12;
}
}
}
}
///
/// Initialize TimePicker object.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public override void OnInitialize()
{
base.OnInitialize();
SetAccessibilityConstructor(Role.DateEditor);
hourPicker = new Picker()
{
MinValue = 1,
MaxValue = 12,
};
hourPicker.ValueChanged += OnHourValueChanged;
minutePicker = new Picker()
{
MinValue = 0,
MaxValue = 59,
};
minutePicker.ValueChanged += OnMinuteValueChanged;
ampmPicker = new Picker()
{
MinValue = 1,
MaxValue = 2,
};
ampmPicker.ValueChanged += OnAmpmValueChanged;
currentTime = DateTime.Now;
if (currentTime.Hour > 12)
{
ampmPicker.CurrentValue = 2;
hourPicker.CurrentValue = currentTime.Hour - 12;
}
else
{
ampmPicker.CurrentValue = 1;
hourPicker.CurrentValue = currentTime.Hour;
}
minutePicker.CurrentValue = currentTime.Minute;
Initialize();
}
///
/// Applies style to TimePicker.
///
/// The style to apply.
[EditorBrowsable(EditorBrowsableState.Never)]
public override void ApplyStyle(ViewStyle viewStyle)
{
base.ApplyStyle(viewStyle);
var timePickerStyle = viewStyle as TimePickerStyle;
if (timePickerStyle == null) return;
//Apply CellPadding.
if (timePickerStyle?.CellPadding != null && Layout != null)
((LinearLayout)Layout).CellPadding = new Size2D(timePickerStyle.CellPadding.Width, timePickerStyle.CellPadding.Height);
//Apply Internal Pickers style.
if (timePickerStyle?.Pickers != null && hourPicker != null && minutePicker != null && ampmPicker != null)
{
hourPicker.ApplyStyle(timePickerStyle.Pickers);
minutePicker.ApplyStyle(timePickerStyle.Pickers);
ampmPicker.ApplyStyle(timePickerStyle.Pickers);
}
}
[SuppressMessage("Microsoft.Reliability",
"CA2000:DisposeObjectsBeforeLosingScope",
Justification = "The CellPadding will be dispose when the time picker disposed")]
private void Initialize()
{
HeightSpecification = LayoutParamPolicies.MatchParent;
Layout = new LinearLayout() {
LinearOrientation = LinearLayout.Orientation.Horizontal,
};
Console.WriteLine("initialize");
is24HourView = false;
PickersOrderSet(false);
SetAmpmText();
}
private void ChangeTime(int hour, int minute, bool hourUpdate)
{
if (hourUpdate)
currentTime = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, hour, currentTime.Minute, 0);
else
currentTime = new DateTime(currentTime.Year, currentTime.Month, currentTime.Day, currentTime.Hour, minute, 0);
}
private void OnHourValueChanged(object sender, ValueChangedEventArgs e)
{
if (currentTime.Hour == e.Value) return;
if (!is24HourView)
{
if (isAm)
{
if (e.Value == 12) ChangeTime(0, 0, true);
else ChangeTime(e.Value, 0, true);
}
else
{
if (e.Value == 12) ChangeTime(12, 0, true);
else ChangeTime(e.Value + 12, 0, true);
}
}
else
ChangeTime(e.Value, 0, true);
OnTimeChanged();
}
private void OnMinuteValueChanged(object sender, ValueChangedEventArgs e)
{
if (currentTime.Minute == e.Value) return;
ChangeTime(0, e.Value, false);
OnTimeChanged();
}
private void OnAmpmValueChanged(object sender, ValueChangedEventArgs e)
{
if ((isAm && e.Value == 1) || (!isAm && e.Value == 2)) return;
if (e.Value == 1)
{ //AM
if (currentTime.Hour == 12) ChangeTime(0, 0, true);
else ChangeTime(currentTime.Hour - 12, 0, true);
isAm = true;
}
else
{ //PM
if (currentTime.Hour == 0) ChangeTime(12, 0, true);
else ChangeTime(currentTime.Hour + 12, 0, true);
isAm = false;
}
OnTimeChanged();
}
private void OnTimeChanged()
{
TimeChangedEventArgs eventArgs = new TimeChangedEventArgs(currentTime);
TimeChanged?.Invoke(this, eventArgs);
}
private void PickersOrderSet(bool ampmForceSet)
{
//FIXME: Check the pickers located in already proper position or not.
Remove(hourPicker);
Remove(minutePicker);
Remove(ampmPicker);
//Get current system locale's time pattern
DateTimeFormatInfo timeFormatInfo = CultureInfo.CurrentCulture.DateTimeFormat;
String timePattern = timeFormatInfo.ShortTimePattern;
String[] timePatternArray = timePattern.Split(' ', ':');
foreach (String format in timePatternArray) {
if (format.IndexOf("H") != -1|| format.IndexOf("h") != -1) Add(hourPicker);
else if (format.IndexOf("M") != -1 || format.IndexOf("m") != -1) Add(minutePicker);
else if (format.IndexOf("t") != -1)
{
is24HourView = false;
ampmForceSet = false;
Add(ampmPicker);
}
}
if (ampmForceSet) Add(ampmPicker);
}
private void SetAmpmText()
{
//FIXME: There is no localeChanged Event for Component now
// AMPM text has to update when system locale changed.
CultureInfo info = CultureInfo.CurrentCulture;
ampmText = new string[] {info.DateTimeFormat.AMDesignator, info.DateTimeFormat.PMDesignator};
ampmPicker.DisplayedValues = new ReadOnlyCollection(ampmText);
}
}
}