diff --git a/tests/app/image-source/image-source-tests.ts b/tests/app/image-source/image-source-tests.ts index c9f4d6052..4b28771e8 100644 --- a/tests/app/image-source/image-source-tests.ts +++ b/tests/app/image-source/image-source-tests.ts @@ -90,7 +90,7 @@ const fullIosPng = "iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAIAAAAmkwkpAAAAAXNSR0IArs4c const fullJpegImage = "/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/2wBDAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQH/wAARCAAEAAQDASIAAhEBAxEB/8QAHwAAAQUBAQEBAQEAAAAAAAAAAAECAwQFBgcICQoL/8QAtRAAAgEDAwIEAwUFBAQAAAF9AQIDAAQRBRIhMUEGE1FhByJxFDKBkaEII0KxwRVS0fAkM2JyggkKFhcYGRolJicoKSo0NTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uHi4+Tl5ufo6erx8vP09fb3+Pn6/8QAHwEAAwEBAQEBAQEBAQAAAAAAAAECAwQFBgcICQoL/8QAtREAAgECBAQDBAcFBAQAAQJ3AAECAxEEBSExBhJBUQdhcRMiMoEIFEKRobHBCSMzUvAVYnLRChYkNOEl8RcYGRomJygpKjU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6goOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4uPk5ebn6Onq8vP09fb3+Pn6/9oADAMBAAIRAxEAPwD+Pz/h5j+1Z/z9fBr/AMRt+AH/AM7uiiiv9fV9E36KOn/HMX0f+n/NlvDT/p3/ANUv/V3vrf8AP1nueaf8LOa9P+ZjjP8Ap3/0/wD6u99b/wD/2Q=="; const expectedJpegStart = "/9j/4AAQSkZJRgAB"; -const expectedPngStart = "iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAIAAAAmkwkpAAAA"; +const expectedPngStart = "iVBORw0KGgoAAAANSUhEUgAAAAQAAAAECAIAAAAmkwkpAAA"; export function testBase64Encode_PNG() { const img = imageSource.fromFile(smallImagePath); diff --git a/tests/app/ui/page/page-tests.ios.ts b/tests/app/ui/page/page-tests.ios.ts index f4dd98309..5227797f3 100644 --- a/tests/app/ui/page/page-tests.ios.ts +++ b/tests/app/ui/page/page-tests.ios.ts @@ -78,6 +78,22 @@ function getNativeHeight(view: View): number { return layout.toDevicePixels(bounds.size.height); } +export function test_correct_layout_top_bottom_edges_does_not_span_not_scrollable_not_flat() { + test_correct_layout_top_bottom_edges_does_not_span_options(false, false); +} + +export function test_correct_layout_top_bottom_edges_does_not_span_scrollable_not_flat() { + test_correct_layout_top_bottom_edges_does_not_span_options(true, false); +} + +export function test_correct_layout_top_bottom_edges_does_not_span_not_scrollable_flat() { + test_correct_layout_top_bottom_edges_does_not_span_options(false, true); +} + +export function test_correct_layout_top_bottom_edges_does_not_span_scrollable_flat() { + test_correct_layout_top_bottom_edges_does_not_span_options(true, true); +} + export function test_correct_layout_scrollable_content_false() { const page = new Page(); topmost().viewController.navigationBar.translucent = true; @@ -251,6 +267,8 @@ export function test_correct_layout_scrollable_content_true_top_edge_does_not_sp const tabItem = new TabViewItem(); tabItem.title = "Item"; const lbl = new Label(); + lbl.viewController = iosView.UILayoutViewController.initWithOwner(new WeakRef(lbl)); + lbl.viewController.edgesForExtendedLayout = UIRectEdge.Bottom | UIRectEdge.Left | UIRectEdge.Right; (lbl).scrollableContent = true; tabItem.view = lbl; tabView.items = [tabItem]; @@ -284,6 +302,8 @@ export function test_correct_layout_scrollable_content_true_bottom_edge_does_not const tabItem = new TabViewItem(); tabItem.title = "Item"; const lbl = new Label(); + lbl.viewController = iosView.UILayoutViewController.initWithOwner(new WeakRef(lbl)); + lbl.viewController.edgesForExtendedLayout = UIRectEdge.Top | UIRectEdge.Left | UIRectEdge.Right; (lbl).scrollableContent = true; tabItem.view = lbl; tabView.items = [tabItem]; @@ -292,11 +312,7 @@ export function test_correct_layout_scrollable_content_true_bottom_edge_does_not helper.navigate(() => page); TKUnit.assertTrue(page.isLoaded, "page NOT loaded!"); TKUnit.assertNotNull(lbl.viewController); - (lbl.viewController).edgesForExtendedLayout = UIRectEdge.Top | UIRectEdge.Left | UIRectEdge.Right; - lbl.requestLayout(); - (lbl.nativeViewProtected).setNeedsLayout(); - (lbl.nativeViewProtected).layoutIfNeeded(); - TKUnit.waitUntilReady(() => lbl.isLayoutValid); + const tabBarHeight = uiUtils.ios.getActualHeight(tabView.viewController.tabBar); const screenHeight = layout.toDevicePixels(UIScreen.mainScreen.bounds.size.height); @@ -307,58 +323,35 @@ export function test_correct_layout_scrollable_content_true_bottom_edge_does_not TKUnit.assertEqual(contentHeight, screenHeight - tabBarHeight, "lbl.height !== screenHeight - tabBarHeight"); } -export function test_correct_layout_top_bottom_edges_does_not_span() { +function test_correct_layout_top_bottom_edges_does_not_span_options(scrollable: boolean, flat: boolean) { const page = new Page(); - page.actionBar.flat = false; - (page).scrollableContent = false; page.actionBar.title = "ActionBar"; - (page.viewController).edgesForExtendedLayout = UIRectEdge.Left | UIRectEdge.Right; const tabView = new TabView(); - (tabView.viewController).edgesForExtendedLayout = UIRectEdge.Left | UIRectEdge.Right; const tabItem = new TabViewItem(); tabItem.title = "Item"; const lbl = new Label(); + lbl.viewController = iosView.UILayoutViewController.initWithOwner(new WeakRef(lbl)); + lbl.viewController.edgesForExtendedLayout = UIRectEdge.Left | UIRectEdge.Right; tabItem.view = lbl; tabView.items = [tabItem]; page.content = tabView; + + page.actionBar.flat = flat; + (page).scrollableContent = scrollable; + (lbl).scrollableContent = scrollable; + helper.navigate(() => page); TKUnit.assertTrue(page.isLoaded, "page NOT loaded!"); - (lbl.viewController).edgesForExtendedLayout = UIRectEdge.Left | UIRectEdge.Right; - lbl.requestLayout(); - (lbl.nativeViewProtected).setNeedsLayout(); - (lbl.nativeViewProtected).layoutIfNeeded(); - TKUnit.waitUntilReady(() => lbl.isLayoutValid); - const statusBarHeight = uiUtils.ios.getStatusBarHeight(page.viewController); const tabBarHeight = uiUtils.ios.getActualHeight(tabView.viewController.tabBar); const screenHeight = layout.toDevicePixels(UIScreen.mainScreen.bounds.size.height); const navBarHeight = uiUtils.ios.getActualHeight(page.frame.ios.controller.navigationBar); - const assert = (scrollable: boolean, flat: boolean) => { - page.actionBar.flat = flat; - (page).scrollableContent = scrollable; - (lbl).scrollableContent = scrollable; - - lbl.requestLayout(); - TKUnit.waitUntilReady(() => lbl.isLayoutValid); - - const pageHeight = getHeight(page); - TKUnit.assertEqual(pageHeight, screenHeight - statusBarHeight - navBarHeight, "page.height !== screenHeight - statusBarHeight - navBarHeight"); - const contentHeight = getHeight(lbl); - TKUnit.assertEqual(contentHeight, screenHeight - statusBarHeight - navBarHeight - tabBarHeight, "lbl.height !== screenHeight - statusBarHeight - navBarHeight - tabBarHeight"); - }; - - // scrollable: false, flat: false; - assert(false, false); - // scrollable: true, flat: false; - assert(true, false); - // scrollable: true, flat: true; - assert(true, true); - // scrollable: false, flat: true; - assert(false, true); + const contentHeight = getHeight(lbl); + TKUnit.assertEqual(contentHeight, screenHeight - statusBarHeight - navBarHeight - tabBarHeight, "lbl.height !== screenHeight - statusBarHeight - navBarHeight - tabBarHeight"); } export function test_showing_native_viewcontroller_doesnt_throw_exception() { diff --git a/tns-core-modules/globals/globals.ts b/tns-core-modules/globals/globals.ts index 3e18ce463..d07e3ada7 100644 --- a/tns-core-modules/globals/globals.ts +++ b/tns-core-modules/globals/globals.ts @@ -30,7 +30,7 @@ const modules: Map = new Map(); (global).moduleResolvers = [global.require]; -global.registerModule = function(name: string, loader: ModuleLoader): void { +global.registerModule = function (name: string, loader: ModuleLoader): void { modules.set(name, loader); } @@ -57,11 +57,20 @@ global.registerWebpackModules = function registerWebpackModules(context: Context const registerName = base + registerExt; if (registerName.startsWith("./") && registerName.endsWith(".js")) { - const jsNickName = registerName.substr(2, registerName.length - 5); - // This is extremely short version like "main-page" that was promoted to be used with global.registerModule("module-name", loaderFunc); - if (isSourceFile || !global.moduleExists(jsNickName)) { - global.registerModule(jsNickName, () => context(key)); - } + const jsNickNames = [ + // This is extremely short version like "main-page" that was promoted to be used with global.registerModule("module-name", loaderFunc); + registerName.substr(2, registerName.length - 5), + // This is for supporting module names like "./main/main-page" + registerName.substr(0, registerName.length - 3), + // This is for supporting module names like "main/main-page.js" + registerName.substr(2), + ]; + + jsNickNames.forEach(jsNickName => { + if (isSourceFile || !global.moduleExists(jsNickName)) { + global.registerModule(jsNickName, () => context(key)); + } + }); } if (isSourceFile || !global.moduleExists(registerName)) { global.registerModule(registerName, () => context(key)); @@ -69,11 +78,11 @@ global.registerWebpackModules = function registerWebpackModules(context: Context }); } -global.moduleExists = function(name: string): boolean { +global.moduleExists = function (name: string): boolean { return modules.has(name); } -global.loadModule = function(name: string): any { +global.loadModule = function (name: string): any { const loader = modules.get(name); if (loader) { return loader(); @@ -110,7 +119,7 @@ global.registerModule("fetch", () => require("fetch")); return new Promise((resolve, reject) => { try { resolve(global.require(path)); - } catch(e) { + } catch (e) { reject(e); } }); diff --git a/tns-core-modules/ui/builder/builder.ts b/tns-core-modules/ui/builder/builder.ts index 56ac43a22..0989b4f3a 100644 --- a/tns-core-modules/ui/builder/builder.ts +++ b/tns-core-modules/ui/builder/builder.ts @@ -47,7 +47,7 @@ export function load(pathOrOptions: string | LoadOptions, context?: any): View { if (typeof pathOrOptions === "string") { componentModule = loadInternal(pathOrOptions); } else { - componentModule = loadCustomComponent(pathOrOptions.path, pathOrOptions.name, pathOrOptions.attributes, pathOrOptions.exports, pathOrOptions.page); + componentModule = loadCustomComponent(pathOrOptions.path, pathOrOptions.name, pathOrOptions.attributes, pathOrOptions.exports, pathOrOptions.page, true); } } else { let path = pathOrOptions; @@ -158,7 +158,7 @@ function loadInternal(fileName: string, context?: any, moduleNamePath?: string): return componentModule; } -function loadCustomComponent(componentPath: string, componentName?: string, attributes?: Object, context?: Object, parentPage?: View): ComponentModule { +function loadCustomComponent(componentPath: string, componentName?: string, attributes?: Object, context?: Object, parentPage?: View, isRootComponent: boolean = true): ComponentModule { if (!parentPage && context) { // Read the parent page that was passed down below // https://github.com/NativeScript/NativeScript/issues/1639 @@ -211,7 +211,7 @@ function loadCustomComponent(componentPath: string, componentName?: string, attr } } else { // Custom components without XML - result = getComponentModule(componentName, componentPath, attributes, context); + result = getComponentModule(componentName, componentPath, attributes, context, undefined, isRootComponent); } // webpack modules require paths to be relative to /app folder. @@ -607,7 +607,7 @@ namespace xml2ui { private buildComponent(args: xml.ParserEvent): ComponentModule { if (args.prefix && args.namespace) { // Custom components - return loadCustomComponent(args.namespace, args.elementName, args.attributes, this.context, this.currentRootView); + return loadCustomComponent(args.namespace, args.elementName, args.attributes, this.context, this.currentRootView, !this.currentRootView); } else { // Default components let namespace = args.namespace; @@ -615,7 +615,7 @@ namespace xml2ui { //Ignore the default ...tns.xsd namespace URL namespace = undefined; } - return getComponentModule(args.elementName, namespace, args.attributes, this.context, this.moduleNamePath); + return getComponentModule(args.elementName, namespace, args.attributes, this.context, this.moduleNamePath, !this.currentRootView); } } diff --git a/tns-core-modules/ui/builder/component-builder/component-builder.d.ts b/tns-core-modules/ui/builder/component-builder/component-builder.d.ts index aee2eb915..51ef44e70 100644 --- a/tns-core-modules/ui/builder/component-builder/component-builder.d.ts +++ b/tns-core-modules/ui/builder/component-builder/component-builder.d.ts @@ -4,7 +4,7 @@ import { View } from "../../core/view"; -export function getComponentModule(elementName: string, namespace: string, attributes: Object, exports: Object, moduleNamePath?: string): ComponentModule; +export function getComponentModule(elementName: string, namespace: string, attributes: Object, exports: Object, moduleNamePath?: string, isRootComponent?: boolean): ComponentModule; export function setPropertyValue(instance: View, instanceModuleExports: Object, pageExports: Object, propertyName: string, propertyValue: any): void; export interface ComponentModule { diff --git a/tns-core-modules/ui/builder/component-builder/component-builder.ts b/tns-core-modules/ui/builder/component-builder/component-builder.ts index 846235232..2ece5eb8e 100644 --- a/tns-core-modules/ui/builder/component-builder/component-builder.ts +++ b/tns-core-modules/ui/builder/component-builder/component-builder.ts @@ -174,13 +174,16 @@ const applyComponentAttributes = profile("applyComponentAttributes", (instance: } }); -export function getComponentModule(elementName: string, namespace: string, attributes: Object, moduleExports: Object, moduleNamePath?: string): ComponentModule { +export function getComponentModule(elementName: string, namespace: string, attributes: Object, moduleExports: Object, moduleNamePath?: string, isRootComponent?: boolean): ComponentModule { // Support lower-case-dashed component declaration in the XML (https://github.com/NativeScript/NativeScript/issues/309). elementName = elementName.split("-").map(s => { return s[0].toUpperCase() + s.substring(1) }).join(""); const { instance, instanceModule } = createComponentInstance(elementName, namespace); moduleExports = getComponentModuleExports(instance, moduleExports, attributes); - applyComponentCss(instance, moduleNamePath, attributes); + if (isRootComponent) { + applyComponentCss(instance, moduleNamePath, attributes); + } + applyComponentAttributes(instance, instanceModule, moduleExports, attributes); var componentModule; diff --git a/tns-core-modules/ui/content-view/content-view.ts b/tns-core-modules/ui/content-view/content-view.ts index baa518790..7f4be8d6b 100644 --- a/tns-core-modules/ui/content-view/content-view.ts +++ b/tns-core-modules/ui/content-view/content-view.ts @@ -1,5 +1,5 @@ import { ContentView as ContentViewDefinition } from "."; -import { View, CustomLayoutView, AddChildFromBuilder, layout } from "../core/view"; +import { View, CustomLayoutView, AddChildFromBuilder, layout, isIOS } from "../core/view"; export * from "../core/view"; @@ -22,7 +22,7 @@ export class ContentView extends CustomLayoutView implements ContentViewDefiniti } this._onContentChanged(oldView, value); - if (oldView !== value) { + if (isIOS && oldView !== value) { this.requestLayout(); } } diff --git a/tns-core-modules/ui/core/view-base/view-base.d.ts b/tns-core-modules/ui/core/view-base/view-base.d.ts index 6751174b0..53baf154a 100644 --- a/tns-core-modules/ui/core/view-base/view-base.d.ts +++ b/tns-core-modules/ui/core/view-base/view-base.d.ts @@ -337,6 +337,11 @@ export abstract class ViewBase extends Observable { */ public _isPaddingRelative: boolean; public _styleScope: any; + + /** + * @private + */ + _isStyleScopeHost: boolean; /** * Determines the depth of suspended updates. diff --git a/tns-core-modules/ui/core/view-base/view-base.ts b/tns-core-modules/ui/core/view-base/view-base.ts index 296bf4e99..3bae66d75 100644 --- a/tns-core-modules/ui/core/view-base/view-base.ts +++ b/tns-core-modules/ui/core/view-base/view-base.ts @@ -178,6 +178,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition private _templateParent: ViewBase; private __nativeView: any; // private _disableNativeViewRecycling: boolean; + public domNode: dnm.DOMNode; public recycleNativeView: "always" | "never" | "auto"; @@ -197,6 +198,7 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition public _styleScope: ssm.StyleScope; public _suspendedUpdates: { [propertyName: string]: Property | CssProperty | CssAnimationProperty }; public _suspendNativeUpdatesCount: SuspendType; + public _isStyleScopeHost: boolean; // Dynamic properties. left: Length; @@ -927,6 +929,12 @@ export abstract class ViewBase extends Observable implements ViewBaseDefinition } _inheritStyleScope(styleScope: ssm.StyleScope): void { + // If we are styleScope don't inherit parent stylescope. + // TODO: Consider adding parent scope and merge selectors. + if (this._isStyleScopeHost) { + return; + } + if (this._styleScope !== styleScope) { this._styleScope = styleScope; this._onCssStateChange(); diff --git a/tns-core-modules/ui/core/view/view-common.ts b/tns-core-modules/ui/core/view/view-common.ts index 28f95bbfa..e78f7a31e 100644 --- a/tns-core-modules/ui/core/view/view-common.ts +++ b/tns-core-modules/ui/core/view/view-common.ts @@ -20,6 +20,7 @@ import { } from "../../gestures"; import { createViewFromEntry } from "../../builder"; +import { StyleScope } from "../../styling/style-scope"; export * from "../../styling/style-properties"; export * from "../view-base"; @@ -74,6 +75,52 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition { public _gestureObservers = {}; + get css(): string { + const scope = this._styleScope; + return scope && scope.css; + } + set css(value: string) { + this.updateStyleScope(undefined, undefined, value); + } + + public addCss(cssString: string): void { + this.updateStyleScope(undefined, cssString); + } + + public addCssFile(cssFileName: string) { + this.updateStyleScope(cssFileName); + } + + private updateStyleScope(cssFileName?: string, cssString?: string, css?: string): void { + let scope = this._styleScope; + if (!scope) { + scope = new StyleScope(); + this.setScopeProperty(scope, cssFileName, cssString, css); + this._inheritStyleScope(scope); + this._isStyleScopeHost = true; + } else { + this.setScopeProperty(scope, cssFileName, cssString, css); + this._onCssStateChange(); + } + } + + private setScopeProperty(scope: StyleScope, cssFileName?: string, cssString?: string, css?: string): void { + if (cssFileName !== undefined) { + scope.addCssFile(cssFileName); + } else if (cssString !== undefined) { + scope.addCss(cssString); + } else if (css !== undefined) { + scope.css = css; + } + } + + _setupAsRootView(context: any): void { + super._setupAsRootView(context); + if (!this._styleScope) { + this.updateStyleScope(); + } + } + observe(type: GestureTypes, callback: (args: GestureEventData) => void, thisArg?: any): void { if (!this._gestureObservers[type]) { this._gestureObservers[type] = []; @@ -157,9 +204,9 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition { const context: any = arguments[1]; const closeCallback: Function = arguments[2]; const fullscreen: boolean = arguments[3]; - const animated = arguments[4]; + const animated = arguments[4]; - const view: ViewDefinition = firstAgrument instanceof ViewCommon + const view: ViewDefinition = firstAgrument instanceof ViewCommon ? firstAgrument : createViewFromEntry({ moduleName: firstAgrument }); (view)._showNativeModalView(this, context, closeCallback, fullscreen, animated); @@ -886,10 +933,6 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition { public _redrawNativeBackground(value: any): void { // } - - addCssFile(cssFileName: string): void { - // TODO: Implement - } } export const automationTextProperty = new Property({ name: "automationText" }); diff --git a/tns-core-modules/ui/core/view/view.android.ts b/tns-core-modules/ui/core/view/view.android.ts index 285456b6b..ac3d181fc 100644 --- a/tns-core-modules/ui/core/view/view.android.ts +++ b/tns-core-modules/ui/core/view/view.android.ts @@ -152,7 +152,7 @@ function initializeDialogFragment() { public onCreateView(inflater: android.view.LayoutInflater, container: android.view.ViewGroup, savedInstanceState: android.os.Bundle): android.view.View { const owner = this.owner; - owner._setupUI(this.getActivity()); + owner._setupAsRootView(this.getActivity()); owner._isAddedToNativeVisualTree = true; return this.owner.nativeViewProtected; @@ -323,7 +323,7 @@ export class View extends ViewCommon { public requestLayout(): void { super.requestLayout(); if (this.nativeViewProtected) { - return this.nativeViewProtected.requestLayout(); + this.nativeViewProtected.requestLayout(); } } diff --git a/tns-core-modules/ui/core/view/view.d.ts b/tns-core-modules/ui/core/view/view.d.ts index af8ae29ab..d96ff0b20 100644 --- a/tns-core-modules/ui/core/view/view.d.ts +++ b/tns-core-modules/ui/core/view/view.d.ts @@ -515,7 +515,7 @@ export abstract class View extends ViewBase { * Returns the current modal view that this page is showing (is parent of), if any. */ modal: View; - + /** * Animates one or more properties of the view based on the supplied options. */ @@ -638,6 +638,20 @@ export abstract class View extends ViewBase { * @private */ _getFragmentManager(): any; /* android.app.FragmentManager */ + + /** + * @private + * A valid css string which will be applied for all nested UI components (based on css rules). + */ + css: string; + + /** + * @private + * Adds a new values to current css. + * @param cssString - A valid css which will be added to current css. + */ + addCss(cssString: string): void; + /** * @private * Adds the content of the file to the current css. @@ -649,12 +663,12 @@ export abstract class View extends ViewBase { /** * __Obsolete:__ There is a new property system that does not rely on _getValue. */ - public _getValue(property: any): never; + _getValue(property: any): never; /** * __Obsolete:__ There is a new property system that does not rely on _setValue. */ - public _setValue(property: any, value: any): never; + _setValue(property: any, value: any): never; } /** diff --git a/tns-core-modules/ui/core/view/view.ios.ts b/tns-core-modules/ui/core/view/view.ios.ts index db7e45152..e7cb9bf6f 100644 --- a/tns-core-modules/ui/core/view/view.ios.ts +++ b/tns-core-modules/ui/core/view/view.ios.ts @@ -57,7 +57,7 @@ export class View extends ViewCommon { super.requestLayout(); this._privateFlags |= PFLAG_FORCE_LAYOUT; - const parent = this.parent; + const parent = this.parent; if (parent) { parent.requestLayout(); } @@ -586,134 +586,45 @@ function isScrollable(controller: UIViewController, owner: View): boolean { const majorVersion = iosUtils.MajorVersion; -interface ExtendedController extends UIViewController { - scrollable: boolean; - navBarHidden: boolean; - hasChildControllers: boolean; - - // safeAreaLeft: NSLayoutConstraint; - // safeAreaTop: NSLayoutConstraint; - // safeAreaRight: NSLayoutConstraint; - // safeAreaBottom: NSLayoutConstraint; - // fullscreenTop: NSLayoutConstraint; - // fullscreenBottom: NSLayoutConstraint; - // fullscreenLeft: NSLayoutConstraint; - // fullscreenRight: NSLayoutConstraint; - // activeConstraints: NSLayoutConstraint[]; -} - export namespace ios { - function constrainView(controller: ExtendedController, owner: View): void { + export function updateConstraints(controller: UIViewController, owner: View): void { const root = controller.view; - + root.autoresizesSubviews = false; + + // const view = controller.view.subviews.length > 0 ? controller.view.subviews[0] : null; + // if (view) { + // view.translatesAutoresizingMaskIntoConstraints = false; + // } + if (!root.safeAreaLayoutGuide) { const layoutGuide = (root).safeAreaLayoutGuide = UILayoutGuide.alloc().init(); root.addLayoutGuide(layoutGuide); - // // view.translatesAutoresizingMaskIntoConstraints = false; - // if (majorVersion > 10) { - // const safeArea = root.safeAreaLayoutGuide; - // layoutGuide.topAnchor.constraintEqualToAnchor(safeArea.topAnchor); - // layoutGuide.bottomAnchor.constraintEqualToAnchor(safeArea.bottomAnchor); - // layoutGuide.leftAnchor.constraintEqualToAnchor(safeArea.leftAnchor); - // layoutGuide.rightAnchor.constraintEqualToAnchor(safeArea.rightAnchor); - // } else { NSLayoutConstraint.activateConstraints([ layoutGuide.topAnchor.constraintEqualToAnchor(controller.topLayoutGuide.bottomAnchor), layoutGuide.bottomAnchor.constraintEqualToAnchor(controller.bottomLayoutGuide.topAnchor), layoutGuide.leadingAnchor.constraintEqualToAnchor(root.leadingAnchor), layoutGuide.trailingAnchor.constraintEqualToAnchor(root.trailingAnchor) ]); - // } } - - // const view = root.subviews[0]; - // if (!controller.safeAreaTop) { - // view.translatesAutoresizingMaskIntoConstraints = false; - // if (majorVersion > 10) { - // const safeArea = root.safeAreaLayoutGuide; - // controller.safeAreaTop = view.topAnchor.constraintEqualToAnchor(safeArea.topAnchor); - // controller.fullscreenTop = view.topAnchor.constraintEqualToAnchor(root.topAnchor); - // controller.safeAreaBottom = view.bottomAnchor.constraintEqualToAnchor(safeArea.bottomAnchor); - // controller.fullscreenBottom = view.bottomAnchor.constraintEqualToAnchor(root.bottomAnchor); - // controller.safeAreaLeft = view.leftAnchor.constraintEqualToAnchor(safeArea.leftAnchor); - // controller.fullscreenLeft = view.leftAnchor.constraintEqualToAnchor(root.leftAnchor); - // controller.safeAreaRight = view.rightAnchor.constraintEqualToAnchor(safeArea.rightAnchor); - // controller.fullscreenRight = view.rightAnchor.constraintEqualToAnchor(root.rightAnchor); - // } else { - // controller.safeAreaTop = view.topAnchor.constraintEqualToAnchor(controller.topLayoutGuide.bottomAnchor); - // controller.fullscreenTop = view.topAnchor.constraintEqualToAnchor(root.topAnchor); - // controller.safeAreaBottom = view.bottomAnchor.constraintEqualToAnchor(controller.bottomLayoutGuide.topAnchor); - // controller.fullscreenBottom = view.bottomAnchor.constraintEqualToAnchor(root.bottomAnchor); - // controller.safeAreaLeft = view.leadingAnchor.constraintEqualToAnchor(root.leadingAnchor); - // controller.fullscreenLeft = controller.safeAreaLeft; - // controller.safeAreaRight = view.trailingAnchor.constraintEqualToAnchor(root.trailingAnchor); - // controller.fullscreenRight = controller.safeAreaRight; - // } - // } - - // // check if this works - // const fullscreenHorizontally = controller === - // iosUtils.getter(UIApplication, UIApplication.sharedApplication).keyWindow.rootViewController - // || !!(owner).wantsFullscreen; - - // const navBarHidden = controller.navBarHidden; - // const scrollable = controller.scrollable;; - // const hasChildControllers = controller.hasChildControllers; - // const constraints = [ - // hasChildControllers || scrollable ? controller.fullscreenBottom : controller.safeAreaBottom, - // fullscreenHorizontally ? controller.fullscreenLeft : controller.safeAreaLeft, - // fullscreenHorizontally ? controller.fullscreenRight : controller.safeAreaRight - // ]; - - // if (hasChildControllers) { - // // If not inner most extend to fullscreen - // constraints.push(controller.fullscreenTop); - // } else if (!scrollable) { - // // If not scrollable dock under safe area - // constraints.push(controller.safeAreaTop); - // } else if (navBarHidden) { - // // If scrollable but no navigation bar dock under safe area - // constraints.push(controller.safeAreaTop); - // } else { - // // If scrollable and navigation bar extend to fullscreen - // constraints.push(controller.fullscreenTop); - // } - - // const activeConstraints = controller.activeConstraints; - // if (activeConstraints) { - // NSLayoutConstraint.deactivateConstraints(activeConstraints); - // } - - // NSLayoutConstraint.activateConstraints(constraints); - // controller.activeConstraints = constraints; } - export function updateConstraints(controller: UIViewController, owner: View): void { - const extendedController = controller; - // const navController = controller.navigationController; - // const navBarHidden = navController ? navController.navigationBarHidden : true; - // const scrollable = isScrollable(controller, owner); - // const hasChildControllers = controller.childViewControllers.count > 0; + function getStatusBarHeight(viewController?: UIViewController): number { + const app = iosUtils.getter(UIApplication, UIApplication.sharedApplication); + if (!app || app.statusBarHidden) { + return 0; + } - // if (extendedController.scrollable !== scrollable - // || extendedController.navBarHidden !== navBarHidden - // || extendedController.hasChildControllers !== hasChildControllers) { - // extendedController.scrollable = scrollable; - // extendedController.navBarHidden = navBarHidden; - // extendedController.hasChildControllers = hasChildControllers; - // constrainView(extendedController, owner); - // } + if (viewController && viewController.prefersStatusBarHidden) { + return 0; + } - constrainView(extendedController, owner); + const statusFrame = app.statusBarFrame; + return Math.min(statusFrame.size.width, statusFrame.size.height); } export function layoutView(controller: UIViewController, owner: View): void { - // const frame = controller.view.subviews[0].bounds; - - // check if this works const fullscreen = controller === iosUtils.getter(UIApplication, UIApplication.sharedApplication).keyWindow.rootViewController; - // || !!(owner).wantsFullscreen; let left: number, top: number, width: number, height: number; @@ -739,28 +650,32 @@ export namespace ios { const safeAreaTopLength = safeOrigin.y - fullscreenOrigin.y; const safeAreaBottomLength = fullscreenSize.height - safeAreaSize.height - safeAreaTopLength; + if (!(controller.edgesForExtendedLayout & UIRectEdge.Top)) { + const statusBarHeight = getStatusBarHeight(controller); + const navBarHeight = controller.navigationController ? controller.navigationController.navigationBar.frame.size.height : 0; + fullscreenOrigin.y = safeOrigin.y; + fullscreenSize.height -= (statusBarHeight + navBarHeight); + } + left = safeOrigin.x; width = safeAreaSize.width; if (hasChildControllers) { // If not inner most extend to fullscreen - top = fullscreenOrigin.y; // constraints.push(controller.fullscreenTop); + top = fullscreenOrigin.y; height = fullscreenSize.height; } else if (!scrollable) { // If not scrollable dock under safe area top = safeOrigin.y; height = safeAreaSize.height; - // constraints.push(controller.safeAreaTop); } else if (navBarHidden) { // If scrollable but no navigation bar dock under safe area - top = safeOrigin.y; // constraints.push(controller.safeAreaTop); - // const adjusted = parentControllerAdjustedScrollViewInsets(controller); - height = safeAreaSize.height + safeAreaBottomLength; - // if () + top = safeOrigin.y; + height = navController ? (fullscreenSize.height - top) : safeAreaSize.height; } else { // If scrollable and navigation bar extend to fullscreen - top = fullscreenOrigin.y; // constraints.push(controller.fullscreenTop); - height = fullscreenOrigin.y + fullscreenSize.height; + top = fullscreenOrigin.y; + height = fullscreenSize.height; } left = layout.toDevicePixels(left); @@ -769,34 +684,10 @@ export namespace ios { height = layout.toDevicePixels(height); } - // const frame = controller.view.safeAreaLayoutGuide.layoutFrame; - // const origin = frame.origin; - // const size = frame.size; - // width = layout.toDevicePixels(fullscreenSize.width); - // height = layout.toDevicePixels(fullscreenSize.height); - - // if (iosUtils.MajorVersion < 11) { - // const window = controller.view.window; - // if (window) { - // const windowSize = window.frame.size; - // const windowInPortrait = windowSize.width < windowSize.height; - // const viewInPortrait = width < height; - // if (windowInPortrait !== viewInPortrait) { - // // NOTE: This happens on iOS <11. - // // We were not visible (probably in backstack) when orientation happened. - // // request layout so we get the new dimensions. - // // There is no sync way to force a layout. - // setTimeout(() => owner.requestLayout()); - // } - // } - // } - const widthSpec = layout.makeMeasureSpec(width, layout.EXACTLY); const heightSpec = layout.makeMeasureSpec(height, layout.EXACTLY); View.measureChild(null, owner, widthSpec, heightSpec); - // const left = layout.toDevicePixels(fullscreenOrigin.x); - // const top = layout.toDevicePixels(fullscreenOrigin.y); View.layoutChild(null, owner, left, top, width + left, height + top); layoutParent(owner.parent); diff --git a/tns-core-modules/ui/frame/frame.android.ts b/tns-core-modules/ui/frame/frame.android.ts index d7ca16e63..715da11cc 100644 --- a/tns-core-modules/ui/frame/frame.android.ts +++ b/tns-core-modules/ui/frame/frame.android.ts @@ -890,10 +890,10 @@ function setActivityContent(activity: android.app.Activity, savedInstanceState: let rootView = callbacks._rootView = (app).rootView; if (!rootView) { const mainEntry = application.getMainEntry(); + const intent = activity.getIntent(); + rootView = notifyLaunch(intent, savedInstanceState); if (shouldCreateRootFrame) { - const intent = activity.getIntent(); const extras = intent.getExtras(); - rootView = notifyLaunch(intent, savedInstanceState); let frameId = -1; // We have extras when we call - new Frame().navigate(); diff --git a/tns-core-modules/ui/layouts/grid-layout/grid-layout-common.ts b/tns-core-modules/ui/layouts/grid-layout/grid-layout-common.ts index 21255d501..a01efb1b1 100644 --- a/tns-core-modules/ui/layouts/grid-layout/grid-layout-common.ts +++ b/tns-core-modules/ui/layouts/grid-layout/grid-layout-common.ts @@ -278,7 +278,7 @@ export class GridLayoutBase extends LayoutBase implements GridLayoutDefinition { } protected invalidate(): void { - this.requestLayout(); + // handled natively in android and overriden in ios. } set rows(value: string) { diff --git a/tns-core-modules/ui/layouts/grid-layout/grid-layout.ios.ts b/tns-core-modules/ui/layouts/grid-layout/grid-layout.ios.ts index 88ceed364..e1c405ff1 100644 --- a/tns-core-modules/ui/layouts/grid-layout/grid-layout.ios.ts +++ b/tns-core-modules/ui/layouts/grid-layout/grid-layout.ios.ts @@ -41,6 +41,11 @@ export class GridLayout extends GridLayoutBase { this.removeFromMap(child); } + protected invalidate(): void { + super.invalidate(); + this.requestLayout(); + } + private getColumnIndex(view: View): number { return Math.max(0, Math.min(GridLayout.getColumn(view), this.columnsInternal.length - 1)); } diff --git a/tns-core-modules/ui/page/page-common.ts b/tns-core-modules/ui/page/page-common.ts index 59c4ad961..7bdf0614a 100644 --- a/tns-core-modules/ui/page/page-common.ts +++ b/tns-core-modules/ui/page/page-common.ts @@ -6,7 +6,6 @@ import { import { Frame, topmost as topmostFrame } from "../frame"; import { ActionBar } from "../action-bar"; import { KeyframeAnimationInfo } from "../animation/keyframe-animation"; -import { StyleScope } from "../styling/style-scope"; import { File, path, knownFolders } from "../../file-system"; import { profile } from "../../profiling"; @@ -28,24 +27,11 @@ export class PageBase extends ContentView implements PageDefinition { public enableSwipeBackNavigation: boolean; public backgroundSpanUnderStatusBar: boolean; public hasActionBar: boolean; - - constructor() { - super(); - this._styleScope = new StyleScope(); - } - + get navigationContext(): any { return this._navigationContext; } - get css(): string { - return this._styleScope.css; - } - set css(value: string) { - this._styleScope.css = value; - this._onCssStateChange(); - } - get actionBar(): ActionBar { if (!this._actionBar) { this.hasActionBar = true; @@ -95,16 +81,6 @@ export class PageBase extends ContentView implements PageDefinition { } } - public addCss(cssString: string): void { - this._styleScope.addCss(cssString); - this._onCssStateChange(); - } - - public addCssFile(cssFileName: string) { - this._styleScope.addCssFile(cssFileName); - this._onCssStateChange(); - } - public getKeyframeAnimationWithName(animationName: string): KeyframeAnimationInfo { return this._styleScope.getKeyframeAnimationWithName(animationName); } @@ -161,10 +137,6 @@ export class PageBase extends ContentView implements PageDefinition { get _childrenCount(): number { return (this.content ? 1 : 0) + (this._actionBar ? 1 : 0); } - - _inheritStyleScope(styleScope: StyleScope): void { - // The Page have its own scope. - } } PageBase.prototype.recycleNativeView = "never"; diff --git a/tns-core-modules/ui/page/page.d.ts b/tns-core-modules/ui/page/page.d.ts index 3b9081f3c..a75c13268 100644 --- a/tns-core-modules/ui/page/page.d.ts +++ b/tns-core-modules/ui/page/page.d.ts @@ -94,23 +94,6 @@ export class Page extends ContentView { */ public enableSwipeBackNavigation: boolean; - /** - * A valid css string which will be applied for all nested UI components (based on css rules). - */ - public css: string; - - /** - * Adds a new values to current css. - * @param cssString - A valid css which will be added to current css. - */ - public addCss(cssString: string): void; - - /** - * Adds the content of the file to the current css. - * @param cssFileName - A valid file name (from the application root) which contains a valid css. - */ - public addCssFile(cssFileName: string): void; - /** * Returns a CSS keyframe animation with the specified name, if it exists. */ 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 a2d0dab6f..ea12cf992 100644 --- a/tns-core-modules/ui/tab-view/tab-view.ios.ts +++ b/tns-core-modules/ui/tab-view/tab-view.ios.ts @@ -141,24 +141,15 @@ function updateItemIconPosition(tabBarItem: UITabBarItem): void { export class TabViewItem extends TabViewItemBase { private __controller: UIViewController; - private _setNeedsLayoutOnSuperview: boolean; + public setViewController(controller: UIViewController, nativeView: UIView) { this.__controller = controller; this.setNativeView(nativeView); - this._setNeedsLayoutOnSuperview = controller.view !== nativeView; - } - - public requestLayout(): void { - super.requestLayout(); - if (this._setNeedsLayoutOnSuperview) { - this.nativeViewProtected.superview.setNeedsLayout(); - } } public disposeNativeView() { this.__controller = undefined; this.setNativeView(undefined); - this._setNeedsLayoutOnSuperview = false; } public _update() {