Merge pull request #1128 from NativeScript/time-picker-min-max

time picker minHour, maxHour, minMinute and maxMinute properties added
This commit is contained in:
Vladimir Enchev
2015-11-23 11:12:31 +02:00
5 changed files with 315 additions and 52 deletions

View File

@ -67,6 +67,24 @@ export function test_WhenCreated_HourIsUndefined() {
});
}
export function test_WhenCreated_MinHourIs1() {
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
var timePicker = <timePickerModule.TimePicker>views[0];
var actualValue = timePicker.minHour;
var expectedValue = 1;
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
});
}
export function test_WhenCreated_MaxHourIs23() {
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
var timePicker = <timePickerModule.TimePicker>views[0];
var actualValue = timePicker.maxHour;
var expectedValue = 23;
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
});
}
export function test_WhenCreated_MinuteIsUndefined() {
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
var timePicker = <timePickerModule.TimePicker>views[0];
@ -76,6 +94,108 @@ export function test_WhenCreated_MinuteIsUndefined() {
});
}
export function test_WhenCreated_MinMinuteIs0() {
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
var timePicker = <timePickerModule.TimePicker>views[0];
var actualValue = timePicker.minMinute;
var expectedValue = 0;
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
});
}
export function test_WhenCreated_MaxMinuteIs59() {
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
var timePicker = <timePickerModule.TimePicker>views[0];
var actualValue = timePicker.maxMinute;
var expectedValue = 59;
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
});
}
export function testHourThrowExceptionWhenLessThanMinHour() {
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
var timePicker = <timePickerModule.TimePicker>views[0];
timePicker.minHour = 13;
TKUnit.assertThrows(function () {
timePicker.hour = timePicker.minHour - 1;
}, "Setting hour property to a value less than minHour property value should throw.");
});
}
export function testHourThrowExceptionWhenGreaterThanMaxHour() {
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
var timePicker = <timePickerModule.TimePicker>views[0];
timePicker.maxHour = 13;
TKUnit.assertThrows(function () {
timePicker.hour = timePicker.maxHour + 1;;
}, "Setting hour property to a value greater than maxHour property value should throw.");
});
}
export function testMinuteThrowExceptionWhenLessThanMinMinute() {
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
var timePicker = <timePickerModule.TimePicker>views[0];
timePicker.minMinute = 13;
TKUnit.assertThrows(function () {
timePicker.minute = timePicker.minMinute - 1;
}, "Setting hour property to a value less than minHour property value should throw.");
});
}
export function testMinuteThrowExceptionWhenGreaterThanMaxMinute() {
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
var timePicker = <timePickerModule.TimePicker>views[0];
timePicker.maxMinute = 13;
TKUnit.assertThrows(function () {
timePicker.minute = timePicker.maxMinute + 1;;
}, "Setting hour property to a value greater than maxHour property value should throw.");
});
}
export function testHourFromNativeEqualToMinHourWhenLessThanMinHour() {
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
var timePicker = <timePickerModule.TimePicker>views[0];
var expectedValue = 13;
timePicker.minHour = expectedValue;
timePickerTestsNative.setNativeHour(timePicker, expectedValue - 1);
var actualValue = timePickerTestsNative.getNativeHour(timePicker);
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
});
}
export function testHourFromNativeEqualToMaxHourWhenGreaterThanMaxHour() {
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
var timePicker = <timePickerModule.TimePicker>views[0];
var expectedValue = 13;
timePicker.maxHour = expectedValue;
timePickerTestsNative.setNativeHour(timePicker, expectedValue + 1);
var actualValue = timePickerTestsNative.getNativeHour(timePicker);
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
});
}
export function testMinuteFromNativeEqualToMinMinuteWhenLessThanMinMinute() {
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
var timePicker = <timePickerModule.TimePicker>views[0];
var expectedValue = 13;
timePicker.minMinute = expectedValue;
timePickerTestsNative.setNativeMinute(timePicker, expectedValue - 1);
var actualValue = timePickerTestsNative.getNativeMinute(timePicker);
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
});
}
export function testMinuteFromNativeEqualToMaxMinuteWhenGreaterThanMaxMinute() {
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
var timePicker = <timePickerModule.TimePicker>views[0];
var expectedValue = 13;
timePicker.maxMinute = expectedValue;
timePickerTestsNative.setNativeMinute(timePicker, expectedValue + 1);
var actualValue = timePickerTestsNative.getNativeMinute(timePicker);
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
});
}
export function testHourFromLocalToNative() {
helper.buildUIAndRunTest(_createTimePicker(), function (views: Array<viewModule.View>) {
var timePicker = <timePickerModule.TimePicker>views[0];

View File

@ -2,10 +2,62 @@
import dependencyObservable = require("ui/core/dependency-observable");
import proxy = require("ui/core/proxy");
import view = require("ui/core/view");
import types = require("utils/types");
function isHourValid(value: number): boolean {
return types.isNumber(value) && value >= 1 && value <= 23;
}
function isMinuteValid(value: number): boolean {
return types.isNumber(value) && value >= 0 && value <= 59;
}
export function getValidHour(hour: number, minHour: number, maxHour: number): number {
let hourValue = hour;
if (minHour && hour < minHour) {
hourValue = minHour
}
if (maxHour && hour > maxHour) {
hourValue = maxHour
}
return hourValue;
}
export function getValidMinute(minute: number, minMinute: number, maxMinute: number): number {
let minuteValue = minute;
if (minMinute && minute < minMinute) {
minuteValue = minMinute
}
if (maxMinute && minute > maxMinute) {
minuteValue = maxMinute
}
return minuteValue;
}
export class TimePicker extends view.View implements definition.TimePicker {
public static hourProperty = new dependencyObservable.Property("hour", "TimePicker", new proxy.PropertyMetadata(undefined));
public static minuteProperty = new dependencyObservable.Property("minute", "TimePicker", new proxy.PropertyMetadata(undefined));
public static hourProperty = new dependencyObservable.Property("hour", "TimePicker",
new proxy.PropertyMetadata(undefined, dependencyObservable.PropertyMetadataSettings.None, undefined, isHourValid));
public static minHourProperty = new dependencyObservable.Property("minHour", "TimePicker",
new proxy.PropertyMetadata(1, dependencyObservable.PropertyMetadataSettings.None, undefined, isHourValid));
public static maxHourProperty = new dependencyObservable.Property("maxHour", "TimePicker",
new proxy.PropertyMetadata(23, dependencyObservable.PropertyMetadataSettings.None, undefined, isHourValid));
public static minuteProperty = new dependencyObservable.Property("minute", "TimePicker",
new proxy.PropertyMetadata(undefined, dependencyObservable.PropertyMetadataSettings.None, undefined, isMinuteValid));
public static minMinuteProperty = new dependencyObservable.Property("minMinute", "TimePicker",
new proxy.PropertyMetadata(0, dependencyObservable.PropertyMetadataSettings.None, undefined, isMinuteValid));
public static maxMinuteProperty = new dependencyObservable.Property("maxMinute", "TimePicker",
new proxy.PropertyMetadata(59, dependencyObservable.PropertyMetadataSettings.None, undefined, isMinuteValid));
constructor() {
super();
@ -24,4 +76,32 @@ export class TimePicker extends view.View implements definition.TimePicker {
set minute(value: number) {
this._setValue(TimePicker.minuteProperty, value);
}
get maxHour(): number {
return this._getValue(TimePicker.maxHourProperty);
}
set maxHour(value: number) {
this._setValue(TimePicker.maxHourProperty, value);
}
get maxMinute(): number {
return this._getValue(TimePicker.maxMinuteProperty);
}
set maxMinute(value: number) {
this._setValue(TimePicker.maxMinuteProperty, value);
}
get minHour(): number {
return this._getValue(TimePicker.minHourProperty);
}
set minHour(value: number) {
this._setValue(TimePicker.minHourProperty, value);
}
get minMinute(): number {
return this._getValue(TimePicker.minMinuteProperty);
}
set minMinute(value: number) {
this._setValue(TimePicker.minMinuteProperty, value);
}
}

View File

@ -2,27 +2,41 @@
import dependencyObservable = require("ui/core/dependency-observable");
import proxy = require("ui/core/proxy");
import utils = require("utils/utils")
import types = require("utils/types")
function onHourPropertyChanged(data: dependencyObservable.PropertyChangeData) {
var picker = <TimePicker>data.object;
picker._setNativeHourSilently(data.newValue);
var validValue = common.getValidHour(data.newValue, picker.minHour, picker.maxHour);
if (validValue === data.newValue) {
picker._setNativeValueSilently(data.newValue, picker.minute);
} else {
throw new Error(`Hour property value (${data.newValue}) is not valid. Min value: (${picker.minHour} ), max value: (${picker.maxHour} ).`);
}
}
(<proxy.PropertyMetadata>common.TimePicker.hourProperty.metadata).onSetNativeValue = onHourPropertyChanged;
function onMinutePropertyChanged(data: dependencyObservable.PropertyChangeData) {
var picker = <TimePicker>data.object;
picker._setNativeMinuteSilently(data.newValue);
var validValue = common.getValidMinute(data.newValue, picker.minMinute, picker.maxMinute);
if (validValue === data.newValue) {
picker._setNativeValueSilently(picker.hour, data.newValue);
} else {
throw new Error(`Minute property value (${data.newValue}) is not valid. Min value: (${picker.minMinute} ), max value: (${picker.maxMinute} ).`);
}
}
(<proxy.PropertyMetadata>common.TimePicker.minuteProperty.metadata).onSetNativeValue = onMinutePropertyChanged;
global.moduleMerge(common, exports);
var SDK = android.os.Build.VERSION.SDK_INT;
export class TimePicker extends common.TimePicker {
private _android: android.widget.TimePicker;
private _listener: android.widget.TimePicker.OnTimeChangedListener;
private _isSettingTime: boolean = false;
get android(): android.widget.TimePicker {
return this._android;
@ -35,51 +49,51 @@ export class TimePicker extends common.TimePicker {
this._listener = new android.widget.TimePicker.OnTimeChangedListener(
<utils.Owned & android.widget.TimePicker.IOnTimeChangedListener>{
get owner() {
return that.get();
},
get owner() {
return that.get();
},
onTimeChanged: function (picker: android.widget.TimePicker, hour: number, minute: number) {
if (this.owner && !this.owner._isSettingTime) {
onTimeChanged: function (picker: android.widget.TimePicker, hour: number, minute: number) {
if (this.owner) {
if (hour !== this.owner.hour) {
this.owner._onPropertyChangedFromNative(common.TimePicker.hourProperty, hour);
}
this.owner._setNativeValueSilently(hour, minute);
if (minute !== this.owner.minute) {
this.owner._onPropertyChangedFromNative(common.TimePicker.minuteProperty, minute);
if (hour !== this.owner.hour) {
this.owner._onPropertyChangedFromNative(common.TimePicker.hourProperty, hour);
}
if (minute !== this.owner.minute) {
this.owner._onPropertyChangedFromNative(common.TimePicker.minuteProperty, minute);
}
}
}
}
});
});
this._android.setOnTimeChangedListener(this._listener);
}
public _setNativeHourSilently(newValue: number) {
if (!this.android) {
return;
}
public _setNativeValueSilently(hour: number, minute: number) {
if (this.android) {
this.android.setOnTimeChangedListener(null);
this._isSettingTime = true;
try {
this.android.setCurrentHour(new java.lang.Integer(newValue));
}
finally {
this._isSettingTime = false;
}
}
if (types.isNumber(hour)) {
var h = new java.lang.Integer(common.getValidHour(hour, this.minHour, this.maxHour));
if (SDK >= 23) {
(<any>this.android).setHour(h);
} else {
this.android.setCurrentHour(h);
}
}
public _setNativeMinuteSilently(newValue: number) {
if (!this.android) {
return;
}
if (types.isNumber(minute)) {
var m = new java.lang.Integer(common.getValidMinute(minute, this.minMinute, this.maxMinute));
if (SDK >= 23) {
(<any>this.android).setMinute(m);
} else {
this.android.setCurrentMinute(m);
}
}
this._isSettingTime = true;
try {
this.android.setCurrentMinute(new java.lang.Integer(newValue));
}
finally {
this._isSettingTime = false;
this.android.setOnTimeChangedListener(this._listener);
}
}
}

View File

@ -33,5 +33,25 @@ declare module "ui/time-picker" {
* Gets or sets the time minute.
*/
minute: number;
/**
* Gets or sets the max time hour.
*/
maxHour: number;
/**
* Gets or sets the max time minute.
*/
maxMinute: number;
/**
* Gets or sets the min time hour.
*/
minHour: number;
/**
* Gets or sets the min time minute.
*/
minMinute: number;
}
}

View File

@ -1,29 +1,42 @@
import common = require("./time-picker-common");
import dependencyObservable = require("ui/core/dependency-observable");
import proxy = require("ui/core/proxy");
import types = require("utils/types");
function getDate(date: NSDate, hour?: number, minute?: number): NSDate {
var comps = NSCalendar.currentCalendar().componentsFromDate(NSCalendarUnit.NSCalendarUnitHour | NSCalendarUnit.NSCalendarUnitMinute, date);
if (hour) {
comps.hour = hour;
}
if (minute) {
comps.minute = minute;
}
return NSCalendar.currentCalendar().dateFromComponents(comps);
}
function onHourPropertyChanged(data: dependencyObservable.PropertyChangeData) {
var picker = <TimePicker>data.object;
if (picker.ios) {
var comps = NSCalendar.currentCalendar().componentsFromDate(NSCalendarUnit.NSCalendarUnitHour | NSCalendarUnit.NSCalendarUnitMinute, picker.ios.date);
comps.hour = data.newValue;
picker.ios.setDateAnimated(NSCalendar.currentCalendar().dateFromComponents(comps), false);
var validValue = common.getValidHour(data.newValue, picker.minHour, picker.maxHour);
if (validValue === data.newValue) {
picker.ios.setDateAnimated(getDate(picker.ios.date, data.newValue, picker.minute), false);
} else {
throw new Error(`Hour property value (${data.newValue}) is not valid. Min value: (${picker.minHour} ), max value: (${picker.maxHour} ).`);
}
}
(<proxy.PropertyMetadata>common.TimePicker.hourProperty.metadata).onSetNativeValue = onHourPropertyChanged;
function onMinutePropertyChanged(data: dependencyObservable.PropertyChangeData) {
var picker = <TimePicker>data.object;
if (picker.ios) {
var comps = NSCalendar.currentCalendar().componentsFromDate(NSCalendarUnit.NSCalendarUnitHour | NSCalendarUnit.NSCalendarUnitMinute, picker.ios.date);
comps.minute = data.newValue;
picker.ios.setDateAnimated(NSCalendar.currentCalendar().dateFromComponents(comps), false);
var validValue = common.getValidMinute(data.newValue, picker.minMinute, picker.maxMinute);
if (validValue === data.newValue) {
picker.ios.setDateAnimated(getDate(picker.ios.date, picker.hour, data.newValue), false);
} else {
throw new Error(`Minute property value (${data.newValue}) is not valid. Min value: (${picker.minMinute} ), max value: (${picker.maxMinute} ).`);
}
}
(<proxy.PropertyMetadata>common.TimePicker.minuteProperty.metadata).onSetNativeValue = onMinutePropertyChanged;
global.moduleMerge(common, exports);
@ -45,6 +58,20 @@ export class TimePicker extends common.TimePicker {
get ios(): UIDatePicker {
return this._ios;
}
public _setNativeValueSilently(hour: number, minute: number) {
if (this.ios) {
this.ios.removeTargetActionForControlEvents(this._changeHandler, "valueChanged", UIControlEvents.UIControlEventValueChanged)
if (types.isNumber(hour) && types.isNumber(minute)) {
this.ios.setDateAnimated(getDate(this.ios.date,
common.getValidHour(hour, this.minHour, this.maxHour),
common.getValidMinute(minute, this.minMinute, this.maxMinute)), false);
}
this.ios.addTargetActionForControlEvents(this._changeHandler, "valueChanged", UIControlEvents.UIControlEventValueChanged);
}
}
}
class UITimePickerChangeHandlerImpl extends NSObject {
@ -64,6 +91,8 @@ class UITimePickerChangeHandlerImpl extends NSObject {
}
var comps = NSCalendar.currentCalendar().componentsFromDate(NSCalendarUnit.NSCalendarUnitHour | NSCalendarUnit.NSCalendarUnitMinute, sender.date);
owner._setNativeValueSilently(comps.hour, comps.minute);
comps = NSCalendar.currentCalendar().componentsFromDate(NSCalendarUnit.NSCalendarUnitHour | NSCalendarUnit.NSCalendarUnitMinute, sender.date);
if (comps.hour !== owner.hour) {
owner._onPropertyChangedFromNative(common.TimePicker.hourProperty, comps.hour);
@ -76,5 +105,5 @@ class UITimePickerChangeHandlerImpl extends NSObject {
public static ObjCExposedMethods = {
'valueChanged': { returns: interop.types.void, params: [UIDatePicker] }
};
}
}