From 058a216ac968ff2ff0c69b18e81f0702d66ef381 Mon Sep 17 00:00:00 2001 From: Hristo Hristov Date: Tue, 19 Dec 2017 16:35:15 +0200 Subject: [PATCH] Move styleScope from Page to View Fix image-source test for API 27 setupAsRootView now makes the component styleScope set css, addCss & addCssFile makes view to be styleScopeHost which cannot be overriden later from parent Android modals now call setupAsRootView Small fixes on ios layouts launch event fired in andriod too Moved some requestLayout calls to ios files where they belongs --- tests/app/image-source/image-source-tests.ts | 2 +- tests/app/ui/page/page-tests.ios.ts | 69 ++++--- tns-core-modules/globals/globals.ts | 27 ++- tns-core-modules/ui/builder/builder.ts | 10 +- .../component-builder/component-builder.d.ts | 2 +- .../component-builder/component-builder.ts | 7 +- .../ui/content-view/content-view.ts | 4 +- .../ui/core/view-base/view-base.d.ts | 5 + .../ui/core/view-base/view-base.ts | 8 + tns-core-modules/ui/core/view/view-common.ts | 55 +++++- tns-core-modules/ui/core/view/view.android.ts | 4 +- tns-core-modules/ui/core/view/view.d.ts | 20 +- tns-core-modules/ui/core/view/view.ios.ts | 171 ++++-------------- tns-core-modules/ui/frame/frame.android.ts | 4 +- .../layouts/grid-layout/grid-layout-common.ts | 2 +- .../ui/layouts/grid-layout/grid-layout.ios.ts | 5 + tns-core-modules/ui/page/page-common.ts | 30 +-- tns-core-modules/ui/page/page.d.ts | 17 -- tns-core-modules/ui/tab-view/tab-view.ios.ts | 11 +- 19 files changed, 185 insertions(+), 268 deletions(-) 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() {