diff --git a/apps/app/package.json b/apps/app/package.json index 711929cac..b83961d5d 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -1,4 +1,4 @@ { "name": "tns-samples-apps", - "main": "ui-tests-app/app.js" + "main": "cuteness.io/app.js" } diff --git a/tns-core-modules/ui/segmented-bar/segmented-bar-common.ts b/tns-core-modules/ui/segmented-bar/segmented-bar-common.ts index bf8a7c7be..694122cd4 100644 --- a/tns-core-modules/ui/segmented-bar/segmented-bar-common.ts +++ b/tns-core-modules/ui/segmented-bar/segmented-bar-common.ts @@ -79,7 +79,6 @@ export abstract class SegmentedBarBase extends View implements SegmentedBarDefin */ export const selectedIndexProperty = new CoercibleProperty({ name: "selectedIndex", defaultValue: -1, - valueConverter: (v) => parseInt(v), valueChanged: (target, oldValue, newValue) => { target.notify({ eventName: SegmentedBarBase.selectedIndexChangedEvent, object: target, oldIndex: oldValue, newIndex: newValue }); }, @@ -95,19 +94,11 @@ export const selectedIndexProperty = new CoercibleProperty parseInt(v) }); selectedIndexProperty.register(SegmentedBarBase); -/** - * Gets or sets the selected background color property of the SegmentedBar. - */ -export const selectedBackgroundColorProperty = new CssProperty({ name: "selectedBackgroundColor", cssName: "selected-background-color", equalityComparer: Color.equals, valueConverter: (v) => new Color(v) }) -selectedBackgroundColorProperty.register(Style); - -/** - * Gets or sets the items dependency property of the SegmentedBar. - */ export const itemsProperty = new Property({ name: "items", valueChanged: (target, oldValue, newValue) => { target.onItemsChanged(oldValue, newValue); @@ -115,3 +106,6 @@ export const itemsProperty = new Property({ name: "selectedBackgroundColor", cssName: "selected-background-color", equalityComparer: Color.equals, valueConverter: (v) => new Color(v) }) +selectedBackgroundColorProperty.register(Style); diff --git a/tns-core-modules/ui/segmented-bar/segmented-bar.ios.ts b/tns-core-modules/ui/segmented-bar/segmented-bar.ios.ts index 59b579380..06b16849b 100644 --- a/tns-core-modules/ui/segmented-bar/segmented-bar.ios.ts +++ b/tns-core-modules/ui/segmented-bar/segmented-bar.ios.ts @@ -34,10 +34,6 @@ export class SegmentedBar extends SegmentedBarBase { return this._ios; } - private insertTab(tabItem: SegmentedBarItem, index: number): void { - - } - get [selectedIndexProperty.native](): number { return -1; } diff --git a/tns-core-modules/ui/tab-view/tab-view-common.ts b/tns-core-modules/ui/tab-view/tab-view-common.ts index 8cbc66d1e..6e09a3da5 100644 --- a/tns-core-modules/ui/tab-view/tab-view-common.ts +++ b/tns-core-modules/ui/tab-view/tab-view-common.ts @@ -1,7 +1,7 @@ -import { TabView as TabViewDefinition, TabViewItem as TabViewItemDefinition } from "ui/tab-view"; +import { TabView as TabViewDefinition, TabViewItem as TabViewItemDefinition, SelectedIndexChangedEventData } from "ui/tab-view"; import { - View, Style, Bindable, Property, CssProperty, CoercibleProperty, - EventData, Color, isIOS, AddArrayFromBuilder + View, ViewBase, Style, Property, CssProperty, CoercibleProperty, + EventData, Color, isIOS, AddArrayFromBuilder, AddChildFromBuilder } from "ui/core/view"; export * from "ui/core/view"; @@ -10,7 +10,7 @@ export const traceCategory = "TabView"; // TODO: Change base class to ViewBase and use addView method to add it. // This way we will support property and binding propagation automatically. -export abstract class TabViewItemBase extends Bindable implements TabViewItemDefinition { +export abstract class TabViewItemBase extends ViewBase implements TabViewItemDefinition { private _title: string = ""; private _view: View; private _iconSource: string; @@ -36,6 +36,7 @@ export abstract class TabViewItemBase extends Bindable implements TabViewItemDef } this._view = value; + this._addView(value); } } @@ -49,6 +50,13 @@ export abstract class TabViewItemBase extends Bindable implements TabViewItemDef } } + public eachChild(callback: (child: ViewBase) => boolean) { + const view = this._view; + if (view) { + callback(view); + } + } + public abstract _update(); } @@ -56,7 +64,7 @@ export module knownCollections { export const items = "items"; } -export class TabViewBase extends View implements TabViewDefinition, AddArrayFromBuilder { +export class TabViewBase extends View implements TabViewDefinition, AddChildFromBuilder, AddArrayFromBuilder { public static selectedIndexChangedEvent = "selectedIndexChanged"; public items: TabViewItemDefinition[]; @@ -64,14 +72,21 @@ export class TabViewBase extends View implements TabViewDefinition, AddArrayFrom public androidOffscreenTabLimit: number; public iosIconRenderingMode: "automatic" | "alwaysOriginal" | "alwaysTemplate"; - protected previousItems: TabViewItemDefinition[]; - public _addArrayFromBuilder(name: string, value: Array) { if (name === "items") { this.items = value; } } + public _addChildFromBuilder(name: string, value: any): void { + if (name === "TabViewItem") { + if (!this.items) { + this.items = new Array(); + } + this.items.push(value); + } + } + public _removeTabs(oldItems: Array) { for (let i = 0, length = oldItems.length; i < length; i++) { let oldItem = oldItems[i]; @@ -83,7 +98,7 @@ export class TabViewBase extends View implements TabViewDefinition, AddArrayFrom if (!oldItem.view) { throw new Error("TabViewItem at index " + i + " does not have a view."); } - this._removeView(oldItem.view); + this._removeView(oldItem); } } @@ -99,7 +114,7 @@ export class TabViewBase extends View implements TabViewDefinition, AddArrayFrom if (!newItem.view) { throw new Error(`TabViewItem at index ${i} does not have a view.`); } - this._addView(newItem.view, i); + this._addView(newItem); } } @@ -116,51 +131,47 @@ export class TabViewBase extends View implements TabViewDefinition, AddArrayFrom return 0; } - public _eachChildView(callback: (child: View) => boolean) { - let items = this.items; + public _eachChildView(callback: (child: ViewBase) => boolean) { + const items = this.items; if (!items) { return; } for (let i = 0, length = items.length; i < length; i++) { let item = items[i]; - if (item.view) { - let retVal = callback(item.view); - if (retVal === false) { - break; - } + if (item) { + callback(item); } } } - // public _onBindingContextChanged(oldValue: any, newValue: any) { - // super._onBindingContextChanged(oldValue, newValue); - // if (this.items && this.items.length > 0) { + public onItemsChanged(oldItems: TabViewItemDefinition[], newItems: TabViewItemDefinition[]): void { + if (oldItems) { + for (let i = 0, count = oldItems.length; i < count; i++) { + this._removeView(oldItems[i]); + } + } - // for (let i = 0, length = this.items.length; i < length; i++) { - // this.items[i].bindingContext = newValue; - // } - // } - // } + if (newItems) { + for (let i = 0, count = newItems.length; i < count; i++) { + const item = newItems[i]; + if (!item) { + throw new Error(`TabViewItem at index ${i} is undefined.`); + } - public onItemsPropertyChanged(oldValue: TabViewItemDefinition[], newValue: TabViewItemDefinition[]) { - this.previousItems = oldValue; + if (!item.view) { + throw new Error(`TabViewItem at index ${i} does not have a view.`); + } + this._addView(item); + } + } } } -export const itemsProperty = new Property({ - name: "items", valueChanged: (target, oldValue, newValue) => { - target.onItemsPropertyChanged(oldValue, newValue); - selectedIndexProperty.coerce(target); - } -}); -itemsProperty.register(TabViewBase); - export const selectedIndexProperty = new CoercibleProperty({ name: "selectedIndex", defaultValue: -1, affectsLayout: isIOS, valueChanged: (target, oldValue, newValue) => { - let args = { eventName: TabViewBase.selectedIndexChangedEvent, object: this, oldIndex: oldValue, newIndex: newValue }; - target.notify(args); + target.notify({ eventName: TabViewBase.selectedIndexChangedEvent, object: this, oldIndex: oldValue, newIndex: newValue }); }, coerceValue: (target, value) => { let items = target.items; @@ -179,7 +190,15 @@ export const selectedIndexProperty = new CoercibleProperty( }); selectedIndexProperty.register(TabViewBase); -export const iosIconRenderingModeProperty = new Property({name: "iosIconRenderingMode", defaultValue: "automatic" }); +export const itemsProperty = new Property({ + name: "items", valueChanged: (target, oldValue, newValue) => { + target.onItemsChanged(oldValue, newValue); + selectedIndexProperty.coerce(target); + } +}); +itemsProperty.register(TabViewBase); + +export const iosIconRenderingModeProperty = new Property({ name: "iosIconRenderingMode", defaultValue: "automatic" }); iosIconRenderingModeProperty.register(TabViewBase); export const androidOffscreenTabLimitProperty = new Property({ diff --git a/tns-core-modules/ui/tab-view/tab-view.d.ts b/tns-core-modules/ui/tab-view/tab-view.d.ts index b69f12407..de95f56e4 100644 --- a/tns-core-modules/ui/tab-view/tab-view.d.ts +++ b/tns-core-modules/ui/tab-view/tab-view.d.ts @@ -2,12 +2,12 @@ * Contains the TabView class, which represents a standard content component with tabs. */ declare module "ui/tab-view" { - import { View, Bindable, Property, CssProperty, Style, EventData, Color } from "ui/core/view"; + import { View, ViewBase, Property, CssProperty, Style, EventData, Color } from "ui/core/view"; /** * Represents a tab view entry. */ - class TabViewItem extends Bindable { + class TabViewItem extends ViewBase { /** * Gets or sets the title of the TabViewItem. */ diff --git a/tns-core-modules/ui/tab-view/tab-view.ios.ts b/tns-core-modules/ui/tab-view/tab-view.ios.ts index 1e1154b96..b8fc2fd06 100644 --- a/tns-core-modules/ui/tab-view/tab-view.ios.ts +++ b/tns-core-modules/ui/tab-view/tab-view.ios.ts @@ -330,7 +330,7 @@ export class TabView extends TabViewBase { const heightMode = layout.getMeasureSpecMode(heightMeasureSpec); this._tabBarHeight = TabView.measureHelper(this._ios.tabBar, width, widthMode, height, heightMode).height; - let moreNavBarVisible = !!this._ios.moreNavigationController.navigationBar.window; + const moreNavBarVisible = !!this._ios.moreNavigationController.navigationBar.window; this._navBarHeight = moreNavBarVisible ? TabView.measureHelper(this._ios.moreNavigationController.navigationBar, width, widthMode, height, heightMode).height : 0; const density = layout.getDisplayDensity(); @@ -346,7 +346,7 @@ export class TabView extends TabViewBase { measureWidth = childSize.measuredWidth; } - let style = this.style; + const style = this.style; measureWidth = Math.max(measureWidth, style.effectiveMinWidth * density); measureHeight = Math.max(measureHeight, style.effectiveMinHeight * density); diff --git a/tns-core-modules/utils/utils-common.ts b/tns-core-modules/utils/utils-common.ts index dc5eaee81..f32515f5a 100644 --- a/tns-core-modules/utils/utils-common.ts +++ b/tns-core-modules/utils/utils-common.ts @@ -58,17 +58,17 @@ export function convertString(value: any): any { export module layout { - var MODE_SHIFT = 30; - var MODE_MASK = 0x3 << MODE_SHIFT; + const MODE_SHIFT = 30; + const MODE_MASK = 0x3 << MODE_SHIFT; - export var UNSPECIFIED = 0 << MODE_SHIFT; - export var EXACTLY = 1 << MODE_SHIFT; - export var AT_MOST = 2 << MODE_SHIFT; + export const UNSPECIFIED = 0 << MODE_SHIFT; + export const EXACTLY = 1 << MODE_SHIFT; + export const AT_MOST = 2 << MODE_SHIFT; - export var MEASURED_HEIGHT_STATE_SHIFT = 0x00000010; /* 16 */ - export var MEASURED_STATE_TOO_SMALL = 0x01000000; - export var MEASURED_STATE_MASK = 0xff000000; - export var MEASURED_SIZE_MASK = 0x00ffffff; + export const MEASURED_HEIGHT_STATE_SHIFT = 0x00000010; /* 16 */ + export const MEASURED_STATE_TOO_SMALL = 0x01000000; + export const MEASURED_STATE_MASK = 0xff000000; + export const MEASURED_SIZE_MASK = 0x00ffffff; export function getMode(mode: number): string { switch (mode) { diff --git a/tns-core-modules/utils/utils.android.ts b/tns-core-modules/utils/utils.android.ts index c9f73467e..a75815bfa 100644 --- a/tns-core-modules/utils/utils.android.ts +++ b/tns-core-modules/utils/utils.android.ts @@ -1,8 +1,60 @@ -import { enabled as traceEnabled, write as traceWrite, categories as traceCategories, - messageType as traceMessageType, notifyEvent as traceNotifyEvent, isCategorySet } from "trace"; +import { + enabled as traceEnabled, write as traceWrite, categories as traceCategories, + messageType as traceMessageType, notifyEvent as traceNotifyEvent, isCategorySet +} from "trace"; export * from "./utils-common"; +export module layout { + let density = -1; + let metrics: android.util.DisplayMetrics; + + // cache the MeasureSpec constants here, to prevent extensive marshaling calls to and from Java + // TODO: While this boosts the performance it is error-prone in case Google changes these constants + const MODE_SHIFT = 30; + const MODE_MASK = 0x3 << MODE_SHIFT; + let sdkVersion = -1; + let useOldMeasureSpec = false; + + export function makeMeasureSpec(size: number, mode: number): number { + if (sdkVersion === -1) { + // check whether the old layout is needed + sdkVersion = ad.getApplicationContext().getApplicationInfo().targetSdkVersion; + useOldMeasureSpec = sdkVersion <= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1; + } + + if (useOldMeasureSpec) { + return size + mode; + } + + return (size & ~MODE_MASK) | (mode & MODE_MASK); + } + + export function getDisplayMetrics(): android.util.DisplayMetrics { + if (!metrics) { + metrics = ad.getApplicationContext().getResources().getDisplayMetrics(); + } + + return metrics; + } + + export function getDisplayDensity(): number { + if (density === -1) { + density = getDisplayMetrics().density; + } + + return density; + } + + export function toDevicePixels(value: number): number { + return value * getDisplayDensity(); + } + + export function toDeviceIndependentPixels(value: number): number { + return value / getDisplayDensity(); + } +} + // We are using "ad" here to avoid namespace collision with the global android object export module ad { let nativeApp: android.app.Application;