Merge pull request #179 from NativeScript/list-picker

List picker
This commit is contained in:
Rossen Hristov
2015-03-16 12:55:13 +02:00
10 changed files with 357 additions and 59 deletions

View File

@@ -123,6 +123,14 @@
<TypeScriptCompile Include="apps\tests\ui\dialogs\dialog-tests.ts" />
<TypeScriptCompile Include="apps\tests\ui\image-cache\image-cache-tests.ts" />
<TypeScriptCompile Include="apps\tests\ui\border\border-tests.ts" />
<TypeScriptCompile Include="apps\tests\ui\list-picker\list-picker-tests-native.d.ts" />
<TypeScriptCompile Include="apps\tests\ui\list-picker\list-picker-tests-native.android.ts">
<DependentUpon>list-picker-tests-native.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="apps\tests\ui\list-picker\list-picker-tests-native.ios.ts">
<DependentUpon>list-picker-tests-native.d.ts</DependentUpon>
</TypeScriptCompile>
<TypeScriptCompile Include="apps\tests\ui\list-picker\list-picker-tests.ts" />
<TypeScriptCompile Include="apps\tests\ui\scroll-view\scroll-view-tests.ts" />
<TypeScriptCompile Include="apps\tests\ui\search-bar\search-bar-tests.ts" />
<TypeScriptCompile Include="apps\tests\ui\style\style-properties-tests.ts" />

View File

@@ -47,6 +47,7 @@ allTests["TEXT-VIEW"] = require("./ui/text-view/text-view-tests");
allTests["FORMATTEDSTRING"] = require("./text/formatted-string-tests");
allTests["FILE-SYSTEM-ACCESS"] = require("./file-system-access-tests/file-system-access-tests");
allTests["XML-DECLARATION"] = require("./xml-declaration/xml-declaration-tests");
allTests["LIST-PICKER"] = require("./ui/list-picker/list-picker-tests");
var testsWithLongDelay = {
testLocation: 10000,

View File

@@ -0,0 +1,17 @@
import listPickerModule = require("ui/list-picker");
export function getNativeItemsCount(listPicker: listPickerModule.ListPicker): number {
var maxValue = listPicker.android.getMaxValue();
if (listPicker.items.length === 0 && maxValue === 0) {
return 0;
}
return maxValue + 1;
}
export function selectNativeItem(listPicker: listPickerModule.ListPicker, index: number): void {
var oldIndex = listPicker.selectedIndex;
listPicker.android.setValue(index);
(<any>listPicker)._valueChangedListener.onValueChange(listPicker.android, oldIndex, index);
}

View File

@@ -0,0 +1,5 @@
//@private
import listPickerModule = require("ui/list-picker");
export declare function getNativeItemsCount(listPicker: listPickerModule.ListPicker): number;
export declare function selectNativeItem(listPicker: listPickerModule.ListPicker, index: number): void;

View File

@@ -0,0 +1,12 @@
import listPickerModule = require("ui/list-picker");
export function getNativeItemsCount(listPicker: listPickerModule.ListPicker): number {
return listPicker.ios.numberOfRowsInComponent(0);
}
export function selectNativeItem(listPicker: listPickerModule.ListPicker, index: number): void {
listPicker.ios.selectRowInComponentAnimated(index, 0, false);
(<UIPickerViewDelegate>(<any>listPicker)._delegate).pickerViewDidSelectRowInComponent(listPicker.ios, index, 0);
}

View File

@@ -0,0 +1,198 @@
import TKUnit = require("../../TKUnit");
import helper = require("../helper");
import viewModule = require("ui/core/view");
import listPickerTestsNative = require("./list-picker-tests-native");
import pageModule = require("ui/page");
// <snippet module="ui/list-picker" title="ListPicker">
// # ListPicker
// Using a ListPicker requires the "ui/list-picker" module.
// ``` JavaScript
import listPickerModule = require("ui/list-picker");
function _createListPicker(): listPickerModule.ListPicker {
// <snippet module="ui/list-picker" title="ListPicker">
// ## Creating a ListPicker
// ``` JavaScript
var listPicker = new listPickerModule.ListPicker();
// ```
// </snippet>
listPicker.id = "ListPicker";
return listPicker;
}
function _createItems(count: number): Array<number> {
var items = new Array<number>();
for (var i = 0; i < count; i++) {
items.push(i);
}
return items;
}
export var testWhenlistPickerIsCreatedItemsAreUndefined = function () {
helper.buildUIAndRunTest(_createListPicker(), function (views: Array<viewModule.View>) {
var listPicker = <listPickerModule.ListPicker>views[0];
var expectedValue = undefined;
var actualValue = listPicker.items;
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
});
}
export var testWhenlistPickerIsCreatedSelectedIndexIsUndefined = function () {
helper.buildUIAndRunTest(_createListPicker(), function (views: Array<viewModule.View>) {
var listPicker = <listPickerModule.ListPicker>views[0];
var expectedValue = undefined;
var actualValue = listPicker.selectedIndex;
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
});
}
export var testWhenSettingItemsToNonEmptyArrayTheSameAmountOfNativeItemsIsCreated = function () {
helper.buildUIAndRunTest(_createListPicker(), function (views: Array<viewModule.View>) {
var listPicker = <listPickerModule.ListPicker>views[0];
listPicker.items = _createItems(10);
var expectedValue = listPicker.items.length;
var actualValue = listPickerTestsNative.getNativeItemsCount(listPicker);
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
});
}
export var testWhenSettingItemsToEmptyArrayZeroNativeItemsAreCreated = function () {
helper.buildUIAndRunTest(_createListPicker(), function (views: Array<viewModule.View>) {
var listPicker = <listPickerModule.ListPicker>views[0];
listPicker.items = [];
var expectedValue = listPicker.items.length;
var actualValue = listPickerTestsNative.getNativeItemsCount(listPicker);
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
});
}
export var testSelectedIndexBecomesZeroWhenItemsBoundToNonEmptyArray = function () {
helper.buildUIAndRunTest(_createListPicker(), function (views: Array<viewModule.View>) {
var listPicker = <listPickerModule.ListPicker>views[0];
// <snippet module="ui/list-picker" title="listPicker">
// ### Binding listPicker.items
// ``` JavaScript
listPicker.items = [1, 2, 3];
// ```
// </snippet>
var expectedValue = 0;
var actualValue = listPicker.selectedIndex;
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
});
}
export var testSelectedIndexBecomesUndefinedWhenItemsBoundToEmptyArray = function () {
helper.buildUIAndRunTest(_createListPicker(), function (views: Array<viewModule.View>) {
var listPicker = <listPickerModule.ListPicker>views[0];
listPicker.items = _createItems(10);
// <snippet module="ui/list-picker" title="listPicker">
// ### Selecting an item programmatically
// ``` JavaScript
listPicker.selectedIndex = 9;
// ```
// </snippet>
listPicker.items = [];
var expectedValue = undefined;
var actualValue = listPicker.selectedIndex;
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
});
}
export var testSelectedIndexBecomesUndefinedWhenItemsBoundToUndefined = function () {
helper.buildUIAndRunTest(_createListPicker(), function (views: Array<viewModule.View>) {
var listPicker = <listPickerModule.ListPicker>views[0];
listPicker.items = _createItems(10);
listPicker.selectedIndex = 9;
listPicker.items = undefined;
var expectedValue = undefined;
var actualValue = listPicker.selectedIndex;
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
});
}
export var testSelectedIndexBecomesUndefinedWhenItemsBoundToNull = function () {
helper.buildUIAndRunTest(_createListPicker(), function (views: Array<viewModule.View>) {
var listPicker = <listPickerModule.ListPicker>views[0];
listPicker.items = _createItems(10);
listPicker.selectedIndex = 9;
listPicker.items = null;
var expectedValue = undefined;
var actualValue = listPicker.selectedIndex;
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
});
}
export var testItemsIsResolvedCorrectlyIfSetBeforeViewIsLoaded = function () {
var listPicker = _createListPicker();
var expectedValue = 10;
listPicker.items = _createItems(expectedValue);
listPicker.selectedIndex = 9;
helper.buildUIAndRunTest(listPicker, function (views: Array<viewModule.View>) {
var listPicker = <listPickerModule.ListPicker>views[0];
var actualValue = listPicker.items.length;
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
});
}
export var testSelectedIndexIsResolvedCorrectlyIfSetBeforeViewIsLoaded = function () {
var listPicker = _createListPicker();
listPicker.items = _createItems(10);
var expectedValue = 9;
listPicker.selectedIndex = expectedValue;
helper.buildUIAndRunTest(listPicker, function (views: Array<viewModule.View>) {
var listPicker = <listPickerModule.ListPicker>views[0];
var actualValue = listPicker.selectedIndex;
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
});
}
export var testSettingNegativeSelectedIndexShouldThrow = function () {
var listPicker = _createListPicker();
helper.buildUIAndRunTest(listPicker, function (views: Array<viewModule.View>) {
var listPicker = <listPickerModule.ListPicker>views[0];
listPicker.items = _createItems(10);
TKUnit.assertThrows(function () {
listPicker.selectedIndex = -1;
}, "Setting selectedIndex to a negative number should throw.");
});
}
export var testSettingSelectedIndexLargerThanCountShouldThrow = function () {
var listPicker = _createListPicker();
helper.buildUIAndRunTest(listPicker, function (views: Array<viewModule.View>) {
var listPicker = <listPickerModule.ListPicker>views[0];
listPicker.items = _createItems(10);
TKUnit.assertThrows(function () {
listPicker.selectedIndex = 10;
}, "Setting selectedIndex to a negative number should throw.");
});
}
export var testWhenSelectingAnItemNativelySelectedIndexIsUpdatedProperly = function () {
var listPicker: listPickerModule.ListPicker;
var mainPage: pageModule.Page;
var pageFactory = function (): pageModule.Page {
listPicker = _createListPicker();
listPicker.items = _createItems(2);
mainPage = new pageModule.Page();
mainPage.content = listPicker;
return mainPage;
};
helper.navigate(pageFactory);
var expectedValue = 1;
listPickerTestsNative.selectNativeItem(listPicker, expectedValue);
TKUnit.wait(helper.ASYNC);
var actualValue = listPicker.selectedIndex;
try {
TKUnit.assert(actualValue === expectedValue, "Actual: " + actualValue + "; Expected: " + expectedValue);
}
finally {
helper.goBack();
}
}

View File

@@ -494,13 +494,13 @@ export var test_binding_cssClass = function () {
property_binding_test("cssClass", "class1", "class2");
}
export var test_binding_style_color = function () {
property_binding_style_test("color", "#FF0000", "#00FF00");
}
//export var test_binding_style_color = function () {
// property_binding_style_test("color", "#FF0000", "#00FF00");
//}
export var test_binding_style_backgroundColor = function () {
property_binding_style_test("backgroundColor", "#FF0000", "#00FF00");
}
//export var test_binding_style_backgroundColor = function () {
// property_binding_style_test("backgroundColor", "#FF0000", "#00FF00");
//}
export var test_binding_style_fontSize = function () {
property_binding_style_test("fontSize", 5, 10);

View File

@@ -3,9 +3,12 @@ import dependencyObservable = require("ui/core/dependency-observable");
import proxy = require("ui/core/proxy");
import view = require("ui/core/view");
import types = require("utils/types");
import trace = require("trace");
export var traceCategory = "ListPicker";
export class ListPicker extends view.View implements definition.ListPicker {
public static selectedIndexProperty = new dependencyObservable.Property("selectedIndex", "ListPicker", new proxy.PropertyMetadata(0));
public static selectedIndexProperty = new dependencyObservable.Property("selectedIndex", "ListPicker", new proxy.PropertyMetadata(undefined));
public static itemsProperty = new dependencyObservable.Property("items", "ListPicker", new proxy.PropertyMetadata(undefined));
constructor() {
@@ -27,6 +30,10 @@ export class ListPicker extends view.View implements definition.ListPicker {
}
public _getItemAsString(index: number): any {
if (!this.items || !this.items.length) {
return "";
}
if (types.isDefined(this.items)) {
var item = this.items.getItem ? this.items.getItem(index) : this.items[index];
@@ -35,4 +42,51 @@ export class ListPicker extends view.View implements definition.ListPicker {
return index.toString();
}
}
public _onSelectedIndexPropertyChanged(data: dependencyObservable.PropertyChangeData) {
trace.write("ListPicker._onSelectedIndexPropertyChanged("+data.oldValue+" => "+data.newValue+");", traceCategory);
var index = this.selectedIndex;
if (types.isUndefined(index)) {
return;
}
if (types.isDefined(this.items)) {
if (index < 0 || index >= this.items.length) {
this.selectedIndex = undefined;
throw new Error("SelectedIndex should be between [0, items.length)");
}
}
}
public _onItemsPropertyChanged(data: dependencyObservable.PropertyChangeData) {
//trace.write("ListPicker._onItemsPropertyChanged(" + data.oldValue + " => " + data.newValue + ");", traceCategory);
}
public _updateSelectedIndexOnItemsPropertyChanged(newItems) {
trace.write("ListPicker._updateSelectedIndexOnItemsPropertyChanged(" + newItems + ");", traceCategory);
var newItemsCount = 0;
if (newItems && newItems.length) {
newItemsCount = newItems.length;
}
if (newItemsCount === 0) {
this.selectedIndex = undefined;
}
else if (types.isUndefined(this.selectedIndex) || this.selectedIndex >= newItemsCount) {
this.selectedIndex = 0;
}
}
}
function onSelectedIndexPropertyChanged(data: dependencyObservable.PropertyChangeData) {
var picker = <ListPicker>data.object;
picker._onSelectedIndexPropertyChanged(data);
}
function onItemsPropertyChanged(data: dependencyObservable.PropertyChangeData) {
var picker = <ListPicker>data.object;
picker._onItemsPropertyChanged(data);
}
(<proxy.PropertyMetadata>ListPicker.selectedIndexProperty.metadata).onSetNativeValue = onSelectedIndexPropertyChanged;
(<proxy.PropertyMetadata>ListPicker.itemsProperty.metadata).onSetNativeValue = onItemsPropertyChanged;

View File

@@ -1,39 +1,15 @@
import common = require("ui/list-picker/list-picker-common");
import dependencyObservable = require("ui/core/dependency-observable");
import proxy = require("ui/core/proxy");
import types = require("utils/types");
function onSelectedIndexPropertyChanged(data: dependencyObservable.PropertyChangeData) {
var picker = <ListPicker>data.object;
if (picker.android && types.isNumber(data.newValue)) {
if (types.isDefined(picker.items) && types.isNumber(picker.items.length)) {
picker.android.setMaxValue(picker.items.length - 1);
}
picker.android.setValue(data.newValue);
}
}
(<proxy.PropertyMetadata>common.ListPicker.selectedIndexProperty.metadata).onSetNativeValue = onSelectedIndexPropertyChanged;
function onItemsPropertyChanged(data: dependencyObservable.PropertyChangeData) {
var picker = <ListPicker>data.object;
if (picker.android && types.isNumber(data.newValue.length)) {
picker.android.setMaxValue(data.newValue.length - 1);
picker.android.setWrapSelectorWheel(false);
}
}
(<proxy.PropertyMetadata>common.ListPicker.itemsProperty.metadata).onSetNativeValue = onItemsPropertyChanged;
// merge the exports of the common file with the exports of this file
declare var exports;
require("utils/module-merge").merge(common, exports);
export class ListPicker extends common.ListPicker {
private _android: android.widget.NumberPicker;
private _valueChangedListener: android.widget.NumberPicker.OnValueChangeListener;
private _formatter: android.widget.NumberPicker.Formatter;
get android(): android.widget.NumberPicker {
return this._android;
@@ -50,7 +26,7 @@ export class ListPicker extends common.ListPicker {
var that = new WeakRef(this);
this._android.setFormatter(new android.widget.NumberPicker.Formatter({
this._formatter = new android.widget.NumberPicker.Formatter({
get owner(): ListPicker {
return that.get();
},
@@ -62,9 +38,10 @@ export class ListPicker extends common.ListPicker {
return index.toString();
}
}));
});
this._android.setFormatter(this._formatter);
this._android.setOnValueChangedListener(new android.widget.NumberPicker.OnValueChangeListener({
this._valueChangedListener = new android.widget.NumberPicker.OnValueChangeListener({
get owner() {
return that.get();
},
@@ -74,11 +51,42 @@ export class ListPicker extends common.ListPicker {
this.owner._onPropertyChangedFromNative(common.ListPicker.selectedIndexProperty, newVal);
}
}
}));
});
this._android.setOnValueChangedListener(this._valueChangedListener);
this._fixDisappearingSelectedItem();
}
public _onSelectedIndexPropertyChanged(data: dependencyObservable.PropertyChangeData) {
super._onSelectedIndexPropertyChanged(data);
if (this.android && types.isNumber(data.newValue)) {
if (types.isDefined(this.items) && types.isNumber(this.items.length)) {
this.android.setMaxValue(this.items.length - 1);
}
this.android.setValue(data.newValue);
}
}
public _onItemsPropertyChanged(data: dependencyObservable.PropertyChangeData) {
if (this.android) {
var maxValue;
if (!data.newValue || !data.newValue.length) {
maxValue = 0;
}
else {
maxValue = data.newValue.length;
}
this.android.setMaxValue(maxValue);
this.android.setWrapSelectorWheel(false);
}
this._updateSelectedIndexOnItemsPropertyChanged(data.newValue);
}
private _fixDisappearingSelectedItem() {
//HACK: http://stackoverflow.com/questions/17708325/android-numberpicker-with-formatter-does-not-format-on-first-rendering/26797732
var mInputTextField = java.lang.Class.forName("android.widget.NumberPicker").getDeclaredField("mInputText");

View File

@@ -1,28 +1,7 @@
import common = require("ui/list-picker/list-picker-common");
import dependencyObservable = require("ui/core/dependency-observable");
import proxy = require("ui/core/proxy");
import types = require("utils/types");
function onSelectedIndexPropertyChanged(data: dependencyObservable.PropertyChangeData) {
var picker = <ListPicker>data.object;
if (picker.ios && types.isNumber(data.newValue)) {
picker.ios.selectRowInComponentAnimated(data.newValue, 0, false);
}
}
(<proxy.PropertyMetadata>common.ListPicker.selectedIndexProperty.metadata).onSetNativeValue = onSelectedIndexPropertyChanged;
function onItemsPropertyChanged(data: dependencyObservable.PropertyChangeData) {
var picker = <ListPicker>data.object;
if (picker.ios) {
picker.ios.reloadAllComponents();
}
}
(<proxy.PropertyMetadata>common.ListPicker.itemsProperty.metadata).onSetNativeValue = onItemsPropertyChanged;
// merge the exports of the common file with the exports of this file
declare var exports;
require("utils/module-merge").merge(common, exports);
@@ -49,6 +28,22 @@ export class ListPicker extends common.ListPicker {
get ios(): UIPickerView {
return this._ios;
}
public _onSelectedIndexPropertyChanged(data: dependencyObservable.PropertyChangeData) {
super._onSelectedIndexPropertyChanged(data);
if (this.ios && types.isNumber(data.newValue)) {
this.ios.selectRowInComponentAnimated(data.newValue, 0, false);
}
}
public _onItemsPropertyChanged(data: dependencyObservable.PropertyChangeData) {
if (this.ios) {
this.ios.reloadAllComponents();
}
this._updateSelectedIndexOnItemsPropertyChanged(data.newValue);
}
}
class ListPickerDataSource extends NSObject implements UIPickerViewDataSource {