From d772d21de074c134f60909f5c8a0ca7a5c2c40c0 Mon Sep 17 00:00:00 2001 From: SvetoslavTsenov Date: Fri, 23 Aug 2019 18:06:47 +0300 Subject: [PATCH 01/11] chore: bump versino to 6.2.0 --- tns-core-modules-widgets/package.json | 6 +++--- tns-core-modules/package.json | 6 +++--- tns-platform-declarations/package.json | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tns-core-modules-widgets/package.json b/tns-core-modules-widgets/package.json index 57c5a34bf..7a5a212c4 100644 --- a/tns-core-modules-widgets/package.json +++ b/tns-core-modules-widgets/package.json @@ -1,6 +1,6 @@ { "name": "tns-core-modules-widgets", - "version": "6.1.0", + "version": "6.2.0", "description": "Native widgets used in the NativeScript framework.", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" @@ -17,8 +17,8 @@ "homepage": "https://github.com/NativeScript/NativeScript/blob/master/tns-core-modules-widgets#readme", "nativescript": { "platforms": { - "ios": "5.0.0", - "android": "5.0.0" + "ios": "6.0.0", + "android": "6.0.0" } } } diff --git a/tns-core-modules/package.json b/tns-core-modules/package.json index e65bcbf73..9e2061a64 100644 --- a/tns-core-modules/package.json +++ b/tns-core-modules/package.json @@ -1,7 +1,7 @@ { "name": "tns-core-modules", "description": "Telerik NativeScript Core Modules", - "version": "6.1.0", + "version": "6.2.0", "homepage": "https://www.nativescript.org", "repository": { "type": "git", @@ -39,8 +39,8 @@ }, "nativescript": { "platforms": { - "ios": "5.0.0", - "android": "5.0.0" + "ios": "6.0.0", + "android": "6.0.0" } }, "snapshot": { diff --git a/tns-platform-declarations/package.json b/tns-platform-declarations/package.json index 920aef4da..83b9b9f7e 100644 --- a/tns-platform-declarations/package.json +++ b/tns-platform-declarations/package.json @@ -1,6 +1,6 @@ { "name": "tns-platform-declarations", - "version": "6.1.0", + "version": "6.2.0", "description": "Platform-specific TypeScript declarations for NativeScript for accessing native objects", "main": "", "scripts": { From 552021373e5de9583fda13a5627eccb91bf9b35f Mon Sep 17 00:00:00 2001 From: Igor Randjelovic Date: Mon, 26 Aug 2019 12:59:03 +0200 Subject: [PATCH 02/11] fix(css): parse css selectors with escape sequences (#7689) --- tests/app/ui/styling/style-tests.ts | 23 +++++++++++++++++++++++ tns-core-modules/css/parser.ts | 8 ++++---- 2 files changed, 27 insertions(+), 4 deletions(-) diff --git a/tests/app/ui/styling/style-tests.ts b/tests/app/ui/styling/style-tests.ts index db4c180c4..d3c5cfa3d 100644 --- a/tests/app/ui/styling/style-tests.ts +++ b/tests/app/ui/styling/style-tests.ts @@ -198,6 +198,29 @@ export function test_class_selector() { TKUnit.assert(btnWithNoClass.style.color === undefined, "Color should not have a value"); } +export function test_class_selector_with_escape_characters() { + let page = helper.getClearCurrentPage(); + let btnWithClass1: buttonModule.Button; + let btnWithClass2: buttonModule.Button; + + page.css = ".test-1 { color: red; } .test-1\\/2 { color: blue }"; + + //// Will be styled + btnWithClass1 = new buttonModule.Button(); + btnWithClass1.className = "test-1"; + + btnWithClass2 = new buttonModule.Button(); + btnWithClass2.className = "test-1/2"; + + const stack = new stackModule.StackLayout(); + page.content = stack; + stack.addChild(btnWithClass1); + stack.addChild(btnWithClass2); + + helper.assertViewColor(btnWithClass1, "#FF0000"); + helper.assertViewColor(btnWithClass2, "#0000FF"); +} + export function test_multiple_class_selector() { let page = helper.getClearCurrentPage(); let btnWithClasses: buttonModule.Button; diff --git a/tns-core-modules/css/parser.ts b/tns-core-modules/css/parser.ts index 5fa7a9919..28d464209 100644 --- a/tns-core-modules/css/parser.ts +++ b/tns-core-modules/css/parser.ts @@ -546,7 +546,7 @@ function parseArgumentsList(text: string, start: number, argument: (value: st } end = arg.end; value.push(arg); - + closingBracketOrCommaRegEx.lastIndex = end; const closingBracketOrComma = closingBracketOrCommaRegEx.exec(text); if (closingBracketOrComma) { @@ -734,7 +734,7 @@ export function parseUniversalSelector(text: string, start: number = 0): Parsed< return { start, end, value: { type: "*" }}; } -const simpleIdentifierSelectorRegEx = /(#|\.|:|\b)([_-\w][_-\w\d]*)/gy; +const simpleIdentifierSelectorRegEx = /(#|\.|:|\b)([_-\w][_-\w\d\\/]*)/gy; export function parseSimpleIdentifierSelector(text: string, start: number = 0): Parsed { simpleIdentifierSelectorRegEx.lastIndex = start; const result = simpleIdentifierSelectorRegEx.exec(text); @@ -743,7 +743,7 @@ export function parseSimpleIdentifierSelector(text: string, start: number = 0): } const end = simpleIdentifierSelectorRegEx.lastIndex; const type = <"#" | "." | ":" | "">result[1]; - const identifier: string = result[2]; + const identifier: string = result[2].replace(/\\/g, ""); const value = { type, identifier }; return { start, end, value }; @@ -1617,4 +1617,4 @@ export class CSSNativeScript { return selectors; } -} \ No newline at end of file +} From ca02ff1aedd76a1384bdbbd34d6f1e10286bc356 Mon Sep 17 00:00:00 2001 From: Nick Iliev Date: Fri, 30 Aug 2019 09:12:59 +0300 Subject: [PATCH 03/11] docs: remove obsolete Waffle.io links from the README (#7759) --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 42e033c35..f20625534 100644 --- a/README.md +++ b/README.md @@ -54,16 +54,16 @@ Below is a common NativeScript architecture diagram. In more detail, read the [H The NativeScript framework consists of a number of components, all of which are open source and on GitHub. Here are the major ones: - **[Cross-platform modules](//github.com/NativeScript/NativeScript/)** - [![npm](https://img.shields.io/npm/dm/tns-core-modules.svg)](https://www.npmjs.com/package/tns-core-modules) [![Waffle.io - NativeScript Modules and Angular](https://badge.waffle.io/NativeScript/NativeScript.svg?columns=In%20Progress)](https://waffle.io/NativeScript/NativeScript) + [![npm](https://img.shields.io/npm/dm/tns-core-modules.svg)](https://www.npmjs.com/package/tns-core-modules) - This repo contains the [NativeScript cross-platform modules](http://docs.nativescript.org/core-concepts/modules), which abstract iOS and Android APIs into JavaScript APIs—e.g. `camera.takePicture()`. The modules are written in TypeScript. - **[iOS runtime](//github.com/NativeScript/ios-runtime/)** - [![npm](https://img.shields.io/npm/dm/tns-ios.svg)](https://www.npmjs.com/package/tns-ios) [![Waffle.io - NativeScript iOS Runtime](https://badge.waffle.io/NativeScript/ios-runtime.svg?columns=In%20Progress)](https://waffle.io/NativeScript/ios-runtime) + [![npm](https://img.shields.io/npm/dm/tns-ios.svg)](https://www.npmjs.com/package/tns-ios) - This repo contains the NativeScript iOS runtime—the code that hosts NativeScript iOS apps, and allows JavaScript code to be executed on iOS devices. The iOS runtime is written in a fun mix of C++, Objective-C, and more. - **[Android runtime](//github.com/NativeScript/android-runtime)** - [![npm](https://img.shields.io/npm/dm/tns-android.svg)](https://www.npmjs.com/package/tns-android) [![Waffle.io - NativeScript Runtimes and CLI](https://badge.waffle.io/NativeScript/android-runtime.svg?columns=In%20Progress)](https://waffle.io/NativeScript/android-runtime) + [![npm](https://img.shields.io/npm/dm/tns-android.svg)](https://www.npmjs.com/package/tns-android) - This repo contains the NativeScript Android—the code that hosts NativeScript Android apps, and allows JavaScript code to be executed on Android devices. The Android runtime is written in a fun mix of C++ and Java. - **[CLI](//github.com/NativeScript/nativescript-cli)** - [![npm](https://img.shields.io/npm/dm/nativescript.svg)](https://www.npmjs.com/package/nativescript) [![Waffle.io - NativeScript CLI](https://badge.waffle.io/NativeScript/nativescript-cli.svg?columns=In%20Progress)](https://waffle.io/NativeScript/nativescript-cli) + [![npm](https://img.shields.io/npm/dm/nativescript.svg)](https://www.npmjs.com/package/nativescript) - This repo contains the NativeScript command-line interface, which lets you create, build, and run apps using the NativeScript framework. The CLI is written in TypeScript. - **[Docs](//github.com/NativeScript/docs)** - This repo contains the NativeScript framework documentation, which is available at . The docs are written in Markdown. From 03d1ff03994bdd469faa810aea115a7d411f4767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Morten=20Sj=C3=B8gren?= Date: Tue, 10 Sep 2019 13:12:04 +0200 Subject: [PATCH 04/11] fix(css-calc): reduce_css_calc_1.default is not a function (#7787) --- tns-core-modules/ui/core/properties/properties.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tns-core-modules/ui/core/properties/properties.ts b/tns-core-modules/ui/core/properties/properties.ts index b79a611fb..527d100bc 100644 --- a/tns-core-modules/ui/core/properties/properties.ts +++ b/tns-core-modules/ui/core/properties/properties.ts @@ -1,4 +1,4 @@ -import reduceCSSCalc from "reduce-css-calc"; +import * as reduceCSSCalc from "reduce-css-calc"; // Definitions. import * as definitions from "../view-base"; From f3d8967e0c78da2d5206c06435262fbeb2e9a792 Mon Sep 17 00:00:00 2001 From: Nikolay Tsonev Date: Tue, 10 Sep 2019 15:57:47 +0300 Subject: [PATCH 05/11] chore: update development workflow info (#7750) --- DevelopmentWorkflow.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/DevelopmentWorkflow.md b/DevelopmentWorkflow.md index b54e0e8da..6e8f810b3 100644 --- a/DevelopmentWorkflow.md +++ b/DevelopmentWorkflow.md @@ -95,13 +95,14 @@ tns run android --path apps ## Running Another App -The [initial setup](#initial-setup) will `npm-link` the `tns-core-modules` globally. You can use it in any local project: - +1. Open the app, where you will use the module from the repository in the console. +2. Add the `tns-core-modules` in the application via: +```bash +npm install --save +# Example: npm install --save ../NativeScript/tns-core-modules +``` +3. Run the app ```bash -# Run once: Link tns-core-modules in your project -npm link tns-core-modules - -# Run the app tns run ios tns run android ``` From e0c49333377a5f85de911a6e952574fb24df71da Mon Sep 17 00:00:00 2001 From: Manol Donev Date: Thu, 12 Sep 2019 14:33:03 +0300 Subject: [PATCH 06/11] chore: merge release to master (#7809) * feat(android): fix tab resource icon size based on spec (#7737) * feat(ios): add icon rendering mode for bottom navigation (#7738) * fix(ios-tabs): crash when add tabstrip in loaded event (#7743) * fix(css): parse css selectors with escape sequences (#7689) (#7732) * fix(ios-tabs): handle nesting proxy view container (#7755) * fix-next(css): className to preserve root views classes (#7725) * docs: cut the 6.1.0 release (#7773) * fix(android-list-picker): NoSuchFieldException on api29 (#7790) * chore: hardcode tslib version to 1.10.0 (#7776) * fix(css-calc): reduce_css_calc_1.default is not a function (#7787) (#7801) --- CHANGELOG.md | 50 ++++++++ .../app/bottom-navigation/binding-page.xml | 2 +- .../bottom-navigation-page.xml | 39 +----- .../bottom-navigation/fancy-fonts-page.xml | 2 +- .../bottom-navigation/icon-change-page.xml | 2 +- package.json | 2 +- .../styling/root-views-css-classes-tests.ts | 120 ++++++++++++++++-- tests/app/ui/styling/style-tests.ts | 30 ++++- .../application/application-common.ts | 19 ++- tns-core-modules/application/application.d.ts | 5 - .../application/application.ios.ts | 22 ++-- tns-core-modules/css/system-classes.d.ts | 30 +++++ tns-core-modules/css/system-classes.ts | 32 +++++ tns-core-modules/package.json | 2 +- .../bottom-navigation.android.ts | 24 ++-- .../bottom-navigation.ios.ts | 18 ++- .../ui/core/view-base/view-base.ts | 33 +++-- tns-core-modules/ui/core/view/view-common.ts | 13 +- tns-core-modules/ui/frame/frame.android.ts | 20 +-- .../ui/list-picker/list-picker.android.ts | 58 ++++++--- tns-core-modules/ui/tabs/tabs.android.ts | 24 ++-- tns-core-modules/ui/tabs/tabs.ios.ts | 48 ++++--- tns-core-modules/ui/utils.android.ts | 2 +- tns-core-modules/ui/utils.d.ts | 1 + tns-core-modules/ui/utils.ios.ts | 2 +- 25 files changed, 416 insertions(+), 184 deletions(-) create mode 100644 tns-core-modules/css/system-classes.d.ts create mode 100644 tns-core-modules/css/system-classes.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ff57aa2f..1acc36b75 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,34 @@ + +# [6.1.0](https://github.com/NativeScript/NativeScript/compare/6.0.7...6.1.0) (2019-09-02) + + +### Bug Fixes + +* dots can now be used in module names ([#7655](https://github.com/NativeScript/NativeScript/issues/7655)) ([b6ff4d3](https://github.com/NativeScript/NativeScript/commit/b6ff4d3)) +* **css:** parse css selectors with escape sequences ([#7689](https://github.com/NativeScript/NativeScript/issues/7689)) ([#7732](https://github.com/NativeScript/NativeScript/issues/7732)) ([e3ed028](https://github.com/NativeScript/NativeScript/commit/e3ed028)) +* **ios-tabs:** handle tabs extended layout for ios 10 ([f7f0612](https://github.com/NativeScript/NativeScript/commit/f7f0612)) +* **ios-tabs:** crash when add tabstrip in loaded event ([#7743](https://github.com/NativeScript/NativeScript/issues/7743)) ([a66f2f2](https://github.com/NativeScript/NativeScript/commit/a66f2f2)) +* **ios-tabs:** handle nesting proxy view container ([#7755](https://github.com/NativeScript/NativeScript/issues/7755)) ([92c3338](https://github.com/NativeScript/NativeScript/commit/92c3338)) +* handle empty folders in non-bundle-compat ([#7649](https://github.com/NativeScript/NativeScript/issues/7649)) ([5fd7913](https://github.com/NativeScript/NativeScript/commit/5fd7913)) + + +### Features + +* implement css-variables and css-calc ([#7553](https://github.com/NativeScript/NativeScript/issues/7553)) ([673c808](https://github.com/NativeScript/NativeScript/commit/673c808)) +* add CSS classes to app/modal root views to target platform/device/orientation/type ([#7606](https://github.com/NativeScript/NativeScript/issues/7606)) ([3adba68](https://github.com/NativeScript/NativeScript/commit/3adba68)) +* **GridLayout:** Add synonym property column[Span] for col[Span] in GridLayout ([#7641](https://github.com/NativeScript/NativeScript/issues/7641)) ([d3c39c1](https://github.com/NativeScript/NativeScript/commit/d3c39c1)) +* apply styles when adding them to the application scope ([#7652](https://github.com/NativeScript/NativeScript/issues/7652)) ([1d12136](https://github.com/NativeScript/NativeScript/commit/1d12136)) +* expose application orientation ([#7602](https://github.com/NativeScript/NativeScript/issues/7602)) ([e2c3c8c](https://github.com/NativeScript/NativeScript/commit/e2c3c8c)) +* **ios-bottom-navigation:** add icon rendering mode ([#7738](https://github.com/NativeScript/NativeScript/issues/7738)) ([ff6d89f](https://github.com/NativeScript/NativeScript/commit/ff6d89f)) +* **android-tabs/bottom-navigation:** fix tab resource icon size based on specification ([#7737](https://github.com/NativeScript/NativeScript/issues/7737)) ([f436b6f](https://github.com/NativeScript/NativeScript/commit/f436b6f)) +* **tabs/bottom-navigation:** introduce TabStrip.isIconSizeFixed property ([#7691](https://github.com/NativeScript/NativeScript/issues/7691)) ([8039c2c](https://github.com/NativeScript/NativeScript/commit/8039c2c)) +* **tabs/bottom-navigation:** add support for custom tabstrip ([#7580](https://github.com/NativeScript/NativeScript/issues/7580)) ([acc3436](https://github.com/NativeScript/NativeScript/commit/acc3436)) +* **tabs/bottom-navigation:** inherit TabContentItem from ContentView ([#7629](https://github.com/NativeScript/NativeScript/issues/7629)) ([72ca461](https://github.com/NativeScript/NativeScript/commit/72ca461)) +* **tabs/bottom-navigation:** flexible font icon usage ([#7672](https://github.com/NativeScript/NativeScript/issues/7672)) ([c0b8db4](https://github.com/NativeScript/NativeScript/commit/c0b8db4)) +* **tabs:** emit tabStripItem tap event ([#7693](https://github.com/NativeScript/NativeScript/issues/7693)) ([b0d1c91](https://github.com/NativeScript/NativeScript/commit/b0d1c91)) +* **tabs/bottom-navigation:** add TabStrip.itemTap event ([#7711](https://github.com/NativeScript/NativeScript/issues/7711)) ([55c9cc9](https://github.com/NativeScript/NativeScript/commit/55c9cc9)) + + ## [6.0.7](https://github.com/NativeScript/NativeScript/compare/6.0.4...6.0.7) (2019-08-22) @@ -32,6 +63,25 @@ + +## [6.0.5](https://github.com/NativeScript/NativeScript/compare/6.0.4...6.0.5) (2019-08-02) + + +### Bug Fixes + +* **observable-array:** splice to notify correct amount of added items ([#7426](https://github.com/NativeScript/NativeScript/issues/7426)) ([5e14de6](https://github.com/NativeScript/NativeScript/commit/5e14de6)) +* added missing openFile method in ios utils ([#7431](https://github.com/NativeScript/NativeScript/issues/7431)) ([cb58cab](https://github.com/NativeScript/NativeScript/commit/cb58cab)) +* full Unicode support in xml ([#7428](https://github.com/NativeScript/NativeScript/issues/7428)) ([b8659e6](https://github.com/NativeScript/NativeScript/commit/b8659e6)) +* **timer:** setTimeout/setInterval support for boolean period ([#7569](https://github.com/NativeScript/NativeScript/issues/7569)) ([a569bb2](https://github.com/NativeScript/NativeScript/commit/a569bb2)) + + +### Features + +* **bottom-navigation-ios:** limit to 5 items ([5815246](https://github.com/NativeScript/NativeScript/commit/5815246)) +* split globals to support smaller worker chunks ([0ee0b67](https://github.com/NativeScript/NativeScript/commit/0ee0b67)) + + + ## [6.0.4](https://github.com/NativeScript/NativeScript/compare/6.0.3...6.0.4) (2019-07-30) diff --git a/e2e/ui-tests-app/app/bottom-navigation/binding-page.xml b/e2e/ui-tests-app/app/bottom-navigation/binding-page.xml index c13ec26c9..20aa4a2da 100644 --- a/e2e/ui-tests-app/app/bottom-navigation/binding-page.xml +++ b/e2e/ui-tests-app/app/bottom-navigation/binding-page.xml @@ -11,7 +11,7 @@ - + diff --git a/e2e/ui-tests-app/app/bottom-navigation/bottom-navigation-page.xml b/e2e/ui-tests-app/app/bottom-navigation/bottom-navigation-page.xml index 66266e701..00fe8dae7 100644 --- a/e2e/ui-tests-app/app/bottom-navigation/bottom-navigation-page.xml +++ b/e2e/ui-tests-app/app/bottom-navigation/bottom-navigation-page.xml @@ -3,23 +3,8 @@ - - - - - + @@ -71,26 +56,4 @@ - - - - - - - - \ No newline at end of file diff --git a/e2e/ui-tests-app/app/bottom-navigation/fancy-fonts-page.xml b/e2e/ui-tests-app/app/bottom-navigation/fancy-fonts-page.xml index 004de8346..7b1657fb9 100644 --- a/e2e/ui-tests-app/app/bottom-navigation/fancy-fonts-page.xml +++ b/e2e/ui-tests-app/app/bottom-navigation/fancy-fonts-page.xml @@ -2,7 +2,7 @@ - + diff --git a/e2e/ui-tests-app/app/bottom-navigation/icon-change-page.xml b/e2e/ui-tests-app/app/bottom-navigation/icon-change-page.xml index 1305f2a06..23442767f 100644 --- a/e2e/ui-tests-app/app/bottom-navigation/icon-change-page.xml +++ b/e2e/ui-tests-app/app/bottom-navigation/icon-change-page.xml @@ -3,7 +3,7 @@ - + diff --git a/package.json b/package.json index 905c56dca..3c57d4ab9 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "shelljs": "^0.7.0", "source-map-support": "^0.4.17", "time-grunt": "1.3.0", - "tslib": "^1.9.3", + "tslib": "1.10.0", "tslint": "^5.4.3", "typedoc": "^0.13.0", "typedoc-plugin-external-module-name": "git://github.com/PanayotCankov/typedoc-plugin-external-module-name.git#with-js", diff --git a/tests/app/ui/styling/root-views-css-classes-tests.ts b/tests/app/ui/styling/root-views-css-classes-tests.ts index aa636f92b..b259f57b5 100644 --- a/tests/app/ui/styling/root-views-css-classes-tests.ts +++ b/tests/app/ui/styling/root-views-css-classes-tests.ts @@ -22,6 +22,7 @@ import { } from "tns-core-modules/ui/core/view/view-common"; import { DeviceType } from "tns-core-modules/ui/enums/enums"; +const CLASS_NAME = "class-name"; const ROOT_CSS_CLASS = "ns-root"; const MODAL_CSS_CLASS = "ns-modal"; const ANDROID_PLATFORM_CSS_CLASS = "ns-android"; @@ -32,18 +33,41 @@ const PORTRAIT_ORIENTATION_CSS_CLASS = "ns-portrait"; const LANDSCAPE_ORIENTATION_CSS_CLASS = "ns-landscape"; const UNKNOWN_ORIENTATION_CSS_CLASS = "ns-unknown"; -export function test_root_view_root_css_class() { - const rootViewCssClasses = getRootView().cssClasses; +function _test_root_view_root_css_class(shouldSetClassName: boolean) { + const rootView = getRootView(); + if (shouldSetClassName) { + rootView.className = CLASS_NAME; + } + const rootViewCssClasses = rootView.cssClasses; TKUnit.assertTrue(rootViewCssClasses.has( ROOT_CSS_CLASS), `${ROOT_CSS_CLASS} CSS class is missing` ); + + if (shouldSetClassName) { + TKUnit.assertTrue(rootViewCssClasses.has( + CLASS_NAME), + `${CLASS_NAME} CSS class is missing` + ); + } } -export function test_root_view_platform_css_class() { - const rootViewCssClasses = getRootView().cssClasses; +export function test_root_view_root_css_class() { + _test_root_view_root_css_class(false); +} +export function test_root_view_class_name_preserve_root_css_class() { + _test_root_view_root_css_class(true); +} + +function _test_root_view_platform_css_class(shouldSetClassName: boolean) { + const rootView = getRootView(); + if (shouldSetClassName) { + rootView.className = CLASS_NAME; + } + + const rootViewCssClasses = rootView.cssClasses; if (isAndroid) { TKUnit.assertTrue(rootViewCssClasses.has( ANDROID_PLATFORM_CSS_CLASS), @@ -63,10 +87,30 @@ export function test_root_view_platform_css_class() { `${ANDROID_PLATFORM_CSS_CLASS} CSS class is present` ); } + + if (shouldSetClassName) { + TKUnit.assertTrue(rootViewCssClasses.has( + CLASS_NAME), + `${CLASS_NAME} CSS class is missing` + ); + } } -export function test_root_view_device_type_css_class() { - const rootViewCssClasses = getRootView().cssClasses; +export function test_root_view_platform_css_class() { + _test_root_view_platform_css_class(false); +} + +export function test_root_view_class_name_preserve_platform_css_class() { + _test_root_view_platform_css_class(true); +} + +function _test_root_view_device_type_css_class(shouldSetClassName: boolean) { + const rootView = getRootView(); + if (shouldSetClassName) { + rootView.className = CLASS_NAME; + } + + const rootViewCssClasses = rootView.cssClasses; const deviceType = device.deviceType; if (deviceType === DeviceType.Phone) { @@ -88,10 +132,30 @@ export function test_root_view_device_type_css_class() { `${PHONE_DEVICE_TYPE_CSS_CLASS} CSS class is present` ); } + + if (shouldSetClassName) { + TKUnit.assertTrue(rootViewCssClasses.has( + CLASS_NAME), + `${CLASS_NAME} CSS class is missing` + ); + } } -export function test_root_view_orientation_css_class() { - const rootViewCssClasses = getRootView().cssClasses; +export function test_root_view_device_type_css_class() { + _test_root_view_device_type_css_class(false); +} + +export function test_root_view_class_name_preserve_device_type_css_class() { + _test_root_view_device_type_css_class(true); +} + +function _test_root_view_orientation_css_class(shouldSetClassName: boolean) { + const rootView = getRootView(); + if (shouldSetClassName) { + rootView.className = CLASS_NAME; + } + + const rootViewCssClasses = rootView.cssClasses; let appOrientation; if (isAndroid) { @@ -140,9 +204,24 @@ export function test_root_view_orientation_css_class() { `${PORTRAIT_ORIENTATION_CSS_CLASS} CSS class is present` ); } + + if (shouldSetClassName) { + TKUnit.assertTrue(rootViewCssClasses.has( + CLASS_NAME), + `${CLASS_NAME} CSS class is missing` + ); + } } -export function test_modal_root_view_modal_css_class() { +export function test_root_view_orientation_css_class() { + _test_root_view_orientation_css_class(false); +} + +export function test_root_view_class_name_preserve_orientation_css_class() { + _test_root_view_orientation_css_class(true); +} + +function _test_modal_root_view_modal_css_class(shouldSetClassName: boolean) { let modalClosed = false; const modalCloseCallback = function () { @@ -153,7 +232,20 @@ export function test_modal_root_view_modal_css_class() { const page = args.object; page.off(View.shownModallyEvent, modalPageShownModallyEventHandler); - TKUnit.assertTrue(_rootModalViews[0].cssClasses.has(MODAL_CSS_CLASS)); + const rootModalView = _rootModalViews[0]; + if (shouldSetClassName) { + rootModalView.className = CLASS_NAME; + } + + const rootModalViewCssClasses = rootModalView.cssClasses; + TKUnit.assertTrue(rootModalViewCssClasses.has(MODAL_CSS_CLASS), + `${MODAL_CSS_CLASS} CSS class is missing`); + + if (shouldSetClassName) { + TKUnit.assertTrue(rootModalViewCssClasses.has(CLASS_NAME), + `${CLASS_NAME} CSS class is missing`); + } + args.closeCallback(); }; @@ -186,3 +278,11 @@ export function test_modal_root_view_modal_css_class() { helper.navigate(hostPageFactory); TKUnit.waitUntilReady(() => modalClosed); } + +export function test_modal_root_view_modal_css_class() { + _test_modal_root_view_modal_css_class(false); +} + +export function test_modal_root_view_class_name_preserve_modal_css_class() { + _test_modal_root_view_modal_css_class(true); +} diff --git a/tests/app/ui/styling/style-tests.ts b/tests/app/ui/styling/style-tests.ts index d3c5cfa3d..004ddeacd 100644 --- a/tests/app/ui/styling/style-tests.ts +++ b/tests/app/ui/styling/style-tests.ts @@ -225,7 +225,7 @@ export function test_multiple_class_selector() { let page = helper.getClearCurrentPage(); let btnWithClasses: buttonModule.Button; - page.css = ".style1 { color: red; } .style2 { background-color: blue } "; + page.css = ".style1 { color: red; } .style2 { background-color: blue; } "; //// Will be styled btnWithClasses = new buttonModule.Button(); @@ -239,6 +239,24 @@ export function test_multiple_class_selector() { helper.assertViewBackgroundColor(btnWithClasses, "#0000FF"); } +export function test_class_selector_overwriting() { + const page = helper.getClearCurrentPage(); + page.css = ".first { color: red; } .second { background-color: blue; }"; + + const btnWithClass = new buttonModule.Button(); + const stack = new stackModule.StackLayout(); + page.content = stack; + stack.addChild(btnWithClass); + + btnWithClass.className = "first"; + helper.assertViewColor(btnWithClass, "#FF0000"); + TKUnit.assert(btnWithClass.style.backgroundColor === undefined, " Background color should not have a value"); + + btnWithClass.className = "second"; + TKUnit.assert(btnWithClass.style.color === undefined, "Color should not have a value"); + helper.assertViewBackgroundColor(btnWithClass, "#0000FF"); +} + export function test_id_selector() { let page = helper.getClearCurrentPage(); page.style.color = unsetValue; @@ -1497,7 +1515,7 @@ export function test_css_calc() { TKUnit.assertEqual(stack.width as any, 125, "Stack - width === 125"); (stack as any).style = `width: calc(100% / 2)`; - TKUnit.assertDeepEqual(stack.width, { unit: "%", value: 0.5 }, "Stack - width === 50%"); + TKUnit.assertDeepEqual(stack.width, { unit: "%", value: 0.5 }, "Stack - width === 50%"); // This should log an error for the invalid css-calc expression, but not cause a crash stack.className = "invalid-css-calc"; @@ -1568,7 +1586,7 @@ export function test_nested_css_calc() { (stack as any).style = `width: calc(100% * calc(1 / 2)`; - TKUnit.assertDeepEqual(stack.width, { unit: "%", value: 0.5 }, "Stack - width === 50%"); + TKUnit.assertDeepEqual(stack.width, { unit: "%", value: 0.5 }, "Stack - width === 50%"); } export function test_css_variables() { @@ -1678,7 +1696,7 @@ export function test_css_calc_and_variables() { // Test setting the CSS variable via the style-attribute, this should override any value set via css-class (stack as any).style = `${cssVarName}: 0.5`; - TKUnit.assertDeepEqual(stack.width, { unit: "%", value: 0.5 }, "Stack - width === 50%"); + TKUnit.assertDeepEqual(stack.width, { unit: "%", value: 0.5 }, "Stack - width === 50%"); } export function test_css_variable_fallback() { @@ -1819,10 +1837,10 @@ export function test_nested_css_calc_and_variables() { // Test setting the CSS variable via the style-attribute, this should override any value set via css-class stack.className = "wide"; (stack as any).style = `${cssVarName}: 0.25`; - TKUnit.assertDeepEqual(stack.width, { unit: "%", value: 0.5 }, "Stack - width === 50%"); + TKUnit.assertDeepEqual(stack.width, { unit: "%", value: 0.5 }, "Stack - width === 50%"); stack.className = "nested"; - TKUnit.assertDeepEqual(stack.width, { unit: "%", value: 1 }, "Stack - width === 100%"); + TKUnit.assertDeepEqual(stack.width, { unit: "%", value: 1 }, "Stack - width === 100%"); } export function test_css_variable_is_applied_to_normal_properties() { diff --git a/tns-core-modules/application/application-common.ts b/tns-core-modules/application/application-common.ts index 6c6a92de4..c59774ea2 100644 --- a/tns-core-modules/application/application-common.ts +++ b/tns-core-modules/application/application-common.ts @@ -40,6 +40,8 @@ import { LoadAppCSSEventData, UnhandledErrorEventData } from "./application"; + +import { CLASS_PREFIX, pushToRootViewCssClasses, removeFromRootViewCssClasses } from "../css/system-classes"; import { DeviceOrientation } from "../ui/enums/enums"; export { UnhandledErrorEventData, DiscardedErrorEventData, CssChangedEventData, LoadAppCSSEventData }; @@ -54,11 +56,10 @@ export const uncaughtErrorEvent = "uncaughtError"; export const discardedErrorEvent = "discardedError"; export const orientationChangedEvent = "orientationChanged"; -export const CSS_CLASS_PREFIX = "ns-"; const ORIENTATION_CSS_CLASSES = [ - `${CSS_CLASS_PREFIX}${DeviceOrientation.portrait}`, - `${CSS_CLASS_PREFIX}${DeviceOrientation.landscape}`, - `${CSS_CLASS_PREFIX}${DeviceOrientation.unknown}` + `${CLASS_PREFIX}${DeviceOrientation.portrait}`, + `${CLASS_PREFIX}${DeviceOrientation.landscape}`, + `${CLASS_PREFIX}${DeviceOrientation.unknown}` ]; let cssFile: string = "./app.css"; @@ -126,9 +127,15 @@ export function loadAppCss(): void { } export function orientationChanged(rootView: View, newOrientation: "portrait" | "landscape" | "unknown"): void { - const newOrientationCssClass = `${CSS_CLASS_PREFIX}${newOrientation}`; + const newOrientationCssClass = `${CLASS_PREFIX}${newOrientation}`; if (!rootView.cssClasses.has(newOrientationCssClass)) { - ORIENTATION_CSS_CLASSES.forEach(c => rootView.cssClasses.delete(c)); + const removeCssClass = (c: string) => { + removeFromRootViewCssClasses(c); + rootView.cssClasses.delete(c); + }; + + ORIENTATION_CSS_CLASSES.forEach(c => removeCssClass(c)); + pushToRootViewCssClasses(newOrientationCssClass); rootView.cssClasses.add(newOrientationCssClass); rootView._onCssStateChange(); } diff --git a/tns-core-modules/application/application.d.ts b/tns-core-modules/application/application.d.ts index 8ef338b76..672e55cc5 100644 --- a/tns-core-modules/application/application.d.ts +++ b/tns-core-modules/application/application.d.ts @@ -53,11 +53,6 @@ export const lowMemoryEvent: string; */ export const orientationChangedEvent: string; -/** - * String value "ns-" used for CSS class prefix. - */ -export const CSS_CLASS_PREFIX: string; - /** * Event data containing information for the application events. */ diff --git a/tns-core-modules/application/application.ios.ts b/tns-core-modules/application/application.ios.ts index 49e9b80cb..37a834096 100644 --- a/tns-core-modules/application/application.ios.ts +++ b/tns-core-modules/application/application.ios.ts @@ -1,4 +1,3 @@ - import { ApplicationEventData, CssChangedEventData, @@ -9,9 +8,8 @@ import { } from "."; import { - CSS_CLASS_PREFIX, displayedEvent, exitEvent, getCssFileName, launchEvent, livesync, - lowMemoryEvent, notify, on, orientationChanged, orientationChangedEvent, resumeEvent, - setApplication, suspendEvent + displayedEvent, exitEvent, getCssFileName, launchEvent, livesync, lowMemoryEvent, notify, on, + orientationChanged, orientationChangedEvent, resumeEvent, setApplication, suspendEvent } from "./application-common"; // First reexport so that app module is initialized. @@ -19,18 +17,15 @@ export * from "./application-common"; // TODO: Remove this and get it from global to decouple builder for angular import { createViewFromEntry } from "../ui/builder"; +import { CLASS_PREFIX, getRootViewCssClasses, pushToRootViewCssClasses } from "../css/system-classes"; import { ios as iosView, View } from "../ui/core/view"; import { Frame, NavigationEntry } from "../ui/frame"; import { device } from "../platform/platform"; import { profile } from "../profiling"; import { ios } from "../utils/utils"; -const ROOT = "root"; const IOS_PLATFORM = "ios"; -const ROOT_VIEW_CSS_CLASSES = [ - `${CSS_CLASS_PREFIX}${ROOT}`, - `${CSS_CLASS_PREFIX}${IOS_PLATFORM}` -]; + const getVisibleViewController = ios.getVisibleViewController; // NOTE: UIResponder with implementation of window - related to https://github.com/NativeScript/ios-runtime/issues/430 @@ -317,9 +312,12 @@ function createRootView(v?: View) { } const deviceType = device.deviceType.toLowerCase(); - ROOT_VIEW_CSS_CLASSES.push(`${CSS_CLASS_PREFIX}${deviceType}`); - ROOT_VIEW_CSS_CLASSES.push(`${CSS_CLASS_PREFIX}${iosApp.orientation}`); - ROOT_VIEW_CSS_CLASSES.forEach(c => rootView.cssClasses.add(c)); + pushToRootViewCssClasses(`${CLASS_PREFIX}${IOS_PLATFORM}`); + pushToRootViewCssClasses(`${CLASS_PREFIX}${deviceType}`); + pushToRootViewCssClasses(`${CLASS_PREFIX}${iosApp.orientation}`); + + const rootViewCssClasses = getRootViewCssClasses(); + rootViewCssClasses.forEach(c => rootView.cssClasses.add(c)); return rootView; } diff --git a/tns-core-modules/css/system-classes.d.ts b/tns-core-modules/css/system-classes.d.ts new file mode 100644 index 000000000..98f7ee59e --- /dev/null +++ b/tns-core-modules/css/system-classes.d.ts @@ -0,0 +1,30 @@ +/** + * @module "system-classes" + */ /** */ + +/** + * String value "ns-" used for CSS system class prefix. + */ +export const CLASS_PREFIX: string; + +/** + * Gets CSS system class for modal root view. + */ +export function getModalRootViewCssClass(): string; + +/** + * Gets CSS system classes for root view. + */ +export function getRootViewCssClasses(): string[]; + +/** + * * Appends new CSS class to the system classes and returns the new length of the array. + * @param value New CSS system class. + */ +export function pushToRootViewCssClasses(value: string): number; + +/** + * Removes CSS class from the system classes and returns it. + * @param value + */ +export function removeFromRootViewCssClasses(value: string): string; diff --git a/tns-core-modules/css/system-classes.ts b/tns-core-modules/css/system-classes.ts new file mode 100644 index 000000000..6e2f7e80c --- /dev/null +++ b/tns-core-modules/css/system-classes.ts @@ -0,0 +1,32 @@ +const MODAL = "modal"; +const ROOT = "root"; + +export const CLASS_PREFIX = "ns-"; + +const modalRootViewCssClass = `${CLASS_PREFIX}${MODAL}`; +const rootViewCssClasses = [`${CLASS_PREFIX}${ROOT}`]; + +export function getModalRootViewCssClass(): string { + return modalRootViewCssClass; +} + +export function getRootViewCssClasses(): string[] { + return rootViewCssClasses; +} + +export function pushToRootViewCssClasses(value: string): number { + rootViewCssClasses.push(value); + + return rootViewCssClasses.length; +} + +export function removeFromRootViewCssClasses(value: string): string { + const index = rootViewCssClasses.indexOf(value); + let removedElement; + + if (index > -1) { + removedElement = rootViewCssClasses.splice(index, 1); + } + + return removedElement; +} diff --git a/tns-core-modules/package.json b/tns-core-modules/package.json index 9e2061a64..f3070f538 100644 --- a/tns-core-modules/package.json +++ b/tns-core-modules/package.json @@ -28,7 +28,7 @@ "dependencies": { "reduce-css-calc": "^2.1.6", "tns-core-modules-widgets": "next", - "tslib": "^1.9.3" + "tslib": "1.10.0" }, "devDependencies": { "@types/node": "~7.0.5", diff --git a/tns-core-modules/ui/bottom-navigation/bottom-navigation.android.ts b/tns-core-modules/ui/bottom-navigation/bottom-navigation.android.ts index 4da582b59..0fafaf048 100644 --- a/tns-core-modules/ui/bottom-navigation/bottom-navigation.android.ts +++ b/tns-core-modules/ui/bottom-navigation/bottom-navigation.android.ts @@ -540,23 +540,15 @@ export class BottomNavigation extends TabNavigationBase { // ICON const iconSource = tabStripItem.image && tabStripItem.image.src; if (iconSource) { - if (iconSource.indexOf(RESOURCE_PREFIX) === 0) { - tabItemSpec.iconId = ad.resources.getDrawableId(iconSource.substr(RESOURCE_PREFIX.length)); - if (tabItemSpec.iconId === 0) { - // TODO: - // traceMissingIcon(iconSource); - } - } else { - const icon = this.getIcon(tabStripItem); + const icon = this.getIcon(tabStripItem); - if (icon) { - // TODO: Make this native call that accepts string so that we don't load Bitmap in JS. - // tslint:disable-next-line:deprecation - tabItemSpec.iconDrawable = icon; - } else { - // TODO: - // traceMissingIcon(iconSource); - } + if (icon) { + // TODO: Make this native call that accepts string so that we don't load Bitmap in JS. + // tslint:disable-next-line:deprecation + tabItemSpec.iconDrawable = icon; + } else { + // TODO: + // traceMissingIcon(iconSource); } } } diff --git a/tns-core-modules/ui/bottom-navigation/bottom-navigation.ios.ts b/tns-core-modules/ui/bottom-navigation/bottom-navigation.ios.ts index 7ea8e43dd..2d2966105 100644 --- a/tns-core-modules/ui/bottom-navigation/bottom-navigation.ios.ts +++ b/tns-core-modules/ui/bottom-navigation/bottom-navigation.ios.ts @@ -531,7 +531,15 @@ export class BottomNavigation extends TabNavigationBase { } private getIconRenderingMode(): UIImageRenderingMode { - return UIImageRenderingMode.AlwaysOriginal; + switch (this.tabStrip && this.tabStrip.iosIconRenderingMode) { + case "alwaysOriginal": + return UIImageRenderingMode.AlwaysOriginal; + case "alwaysTemplate": + return UIImageRenderingMode.AlwaysTemplate; + case "automatic": + default: + return UIImageRenderingMode.Automatic; + } } private getIcon(tabStripItem: TabStripItem): UIImage { @@ -547,10 +555,12 @@ export class BottomNavigation extends TabNavigationBase { const color = target.style.color; const iconTag = [iconSource, font.fontStyle, font.fontWeight, font.fontSize, font.fontFamily, color].join(";"); + let isFontIcon = false; let image: UIImage = this._iconsCache[iconTag]; if (!image) { let is = new ImageSource; if (isFontIconURI(iconSource)) { + isFontIcon = true; const fontIconCode = iconSource.split("//")[1]; is = fromFontIconCode(fontIconCode, font, color); } else { @@ -564,7 +574,11 @@ export class BottomNavigation extends TabNavigationBase { image = this.getFixedSizeIcon(image); } - const originalRenderedImage = image.imageWithRenderingMode(this.getIconRenderingMode()); + let renderingMode: UIImageRenderingMode = UIImageRenderingMode.AlwaysOriginal; + if (!isFontIcon) { + renderingMode = this.getIconRenderingMode(); + } + const originalRenderedImage = image.imageWithRenderingMode(renderingMode); this._iconsCache[iconTag] = originalRenderedImage; image = originalRenderedImage; } else { 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 06ec4c996..89dc23607 100644 --- a/tns-core-modules/ui/core/view-base/view-base.ts +++ b/tns-core-modules/ui/core/view-base/view-base.ts @@ -1,10 +1,13 @@ // Definitions. import { ViewBase as ViewBaseDefinition } from "."; +import { + AlignSelf, FlexGrow, FlexShrink, FlexWrapBefore, Order +} from "../../layouts/flexbox-layout"; import { Page } from "../../page"; -import { Order, FlexGrow, FlexShrink, FlexWrapBefore, AlignSelf } from "../../layouts/flexbox-layout"; // Types. import { Property, CssProperty, CssAnimationProperty, InheritedProperty, Style, clearInheritedProperties, propagateInheritableProperties, propagateInheritableCssProperties, initNativeView } from "../properties"; +import { getModalRootViewCssClass, getRootViewCssClasses } from "../../../css/system-classes"; import { Source } from "../../../utils/debug"; import { Binding, BindingOptions, Observable, WrappedValue, PropertyChangeData, traceEnabled, traceWrite, traceCategories } from "../bindable"; import { isIOS, isAndroid } from "../../../platform"; @@ -22,10 +25,9 @@ export { isIOS, isAndroid, layout, Color }; export * from "../bindable"; export * from "../properties"; +import * as dnm from "../../../debugger/dom-node"; import * as ssm from "../../styling/style-scope"; -// import { DOMNode } from "../../../debugger/dom-node"; -import * as dnm from "../../../debugger/dom-node"; let domNodeModule: typeof dnm; function ensuredomNodeModule(): void { @@ -1036,11 +1038,26 @@ bindingContextProperty.register(ViewBase); export const classNameProperty = new Property({ name: "className", valueChanged(view: ViewBase, oldValue: string, newValue: string) { - let classes = view.cssClasses; - classes.clear(); - if (typeof newValue === "string" && newValue !== "") { - newValue.split(" ").forEach(c => classes.add(c)); + const cssClasses = view.cssClasses; + + const modalViewCssClass = getModalRootViewCssClass(); + const rootViewCssClasses = getRootViewCssClasses(); + + const shouldAddModalRootViewCssClass = cssClasses.has(modalViewCssClass); + const shouldAddRootViewCssClasses = cssClasses.has(rootViewCssClasses[0]); + + cssClasses.clear(); + + if (shouldAddModalRootViewCssClass) { + cssClasses.add(modalViewCssClass); + } else if (shouldAddRootViewCssClasses) { + rootViewCssClasses.forEach(c => cssClasses.add(c)); } + + if (typeof newValue === "string" && newValue !== "") { + newValue.split(" ").forEach(c => cssClasses.add(c)); + } + view._onCssStateChange(); } }); @@ -1058,4 +1075,4 @@ export function booleanConverter(v: string): boolean { } throw new Error(`Invalid boolean: ${v}`); -} \ No newline at end of file +} diff --git a/tns-core-modules/ui/core/view/view-common.ts b/tns-core-modules/ui/core/view/view-common.ts index d09e09929..4e9352358 100644 --- a/tns-core-modules/ui/core/view/view-common.ts +++ b/tns-core-modules/ui/core/view/view-common.ts @@ -5,9 +5,8 @@ import { } from "."; import { - ViewBase, Property, booleanConverter, EventData, layout, - getEventOrGestureName, traceEnabled, traceWrite, traceCategories, - InheritedProperty, ShowModalOptions + booleanConverter, EventData, getEventOrGestureName, InheritedProperty, layout, + Property, ShowModalOptions, traceCategories, traceEnabled, traceWrite, ViewBase } from "../view-base"; import { HorizontalAlignment, VerticalAlignment, Visibility, Length, PercentLength } from "../../styling/style-properties"; @@ -20,6 +19,7 @@ import { fromString as gestureFromString } from "../../gestures"; +import { getModalRootViewCssClass } from "../../../css/system-classes"; import { createViewFromEntry } from "../../builder"; import { sanitizeModuleName } from "../../builder/module-name-sanitizer"; import { StyleScope } from "../../styling/style-scope"; @@ -31,9 +31,6 @@ export * from "../view-base"; export { LinearGradient }; import * as am from "../../animation"; -import { CSS_CLASS_PREFIX } from "../../../application"; - -const MODAL = "modal"; let animationModule: typeof am; function ensureAnimationModule() { @@ -373,7 +370,9 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition { protected _showNativeModalView(parent: ViewCommon, options: ShowModalOptions) { _rootModalViews.push(this); - this.cssClasses.add(`${CSS_CLASS_PREFIX}${MODAL}`); + + const modalRootViewCssClass = getModalRootViewCssClass(); + this.cssClasses.add(modalRootViewCssClass); parent._modal = this; this._modalParent = parent; diff --git a/tns-core-modules/ui/frame/frame.android.ts b/tns-core-modules/ui/frame/frame.android.ts index f93d9a874..fc52f37b8 100644 --- a/tns-core-modules/ui/frame/frame.android.ts +++ b/tns-core-modules/ui/frame/frame.android.ts @@ -7,9 +7,10 @@ import { Page } from "../page"; // Types. import * as application from "../../application"; + import { - FrameBase, goBack, _stack, NavigationType, - Observable, View, traceCategories, traceEnabled, traceError, traceWrite + _stack, FrameBase, goBack, NavigationType, Observable, + traceCategories, traceEnabled, traceError, traceWrite, View } from "./frame-common"; import { @@ -19,6 +20,7 @@ import { // TODO: Remove this and get it from global to decouple builder for angular import { createViewFromEntry } from "../builder"; +import { CLASS_PREFIX, getRootViewCssClasses, pushToRootViewCssClasses } from "../../css/system-classes"; import { device } from "../../platform/platform"; import { profile } from "../../profiling"; @@ -32,12 +34,7 @@ interface AnimatorState { transitionName: string; } -const ROOT = "root"; const ANDROID_PLATFORM = "android"; -const ROOT_VIEW_CSS_CLASSES = [ - `${application.CSS_CLASS_PREFIX}${ROOT}`, - `${application.CSS_CLASS_PREFIX}${ANDROID_PLATFORM}` -]; const INTENT_EXTRA = "com.tns.activity"; const ROOT_VIEW_ID_EXTRA = "com.tns.activity.rootViewId"; @@ -1289,9 +1286,12 @@ class ActivityCallbacksImplementation implements AndroidActivityCallbacks { activityRootViewsMap.set(rootView._domId, new WeakRef(rootView)); const deviceType = device.deviceType.toLowerCase(); - ROOT_VIEW_CSS_CLASSES.push(`${application.CSS_CLASS_PREFIX}${deviceType}`); - ROOT_VIEW_CSS_CLASSES.push(`${application.CSS_CLASS_PREFIX}${application.android.orientation}`); - ROOT_VIEW_CSS_CLASSES.forEach(c => this._rootView.cssClasses.add(c)); + pushToRootViewCssClasses(`${CLASS_PREFIX}${ANDROID_PLATFORM}`); + pushToRootViewCssClasses(`${CLASS_PREFIX}${deviceType}`); + pushToRootViewCssClasses(`${CLASS_PREFIX}${application.android.orientation}`); + + const rootViewCssClasses = getRootViewCssClasses(); + rootViewCssClasses.forEach(c => this._rootView.cssClasses.add(c)); } // Initialize native visual tree; diff --git a/tns-core-modules/ui/list-picker/list-picker.android.ts b/tns-core-modules/ui/list-picker/list-picker.android.ts index ccc9ea5e1..328af50fd 100644 --- a/tns-core-modules/ui/list-picker/list-picker.android.ts +++ b/tns-core-modules/ui/list-picker/list-picker.android.ts @@ -1,8 +1,12 @@ import { ListPickerBase, selectedIndexProperty, itemsProperty, colorProperty, Color } from "./list-picker-common"; import { ItemsSource } from "."; +import { device } from "../../platform"; +import lazy from "../../utils/lazy"; export * from "./list-picker-common"; +const sdkVersion = lazy(() => parseInt(device.sdkVersion)); + interface Formatter { new (owner: ListPicker): android.widget.NumberPicker.Formatter; } @@ -90,7 +94,14 @@ export class ListPicker extends ListPickerBase { super.initNativeView(); initializeNativeClasses(); const nativeView = this.nativeViewProtected; - this._selectorWheelPaint = getSelectorWheelPaint(nativeView); + + // api28 and lower uses reflection to retrieve and manipulate + // android.graphics.Paint object; this is no longer allowed on newer api levels but + // equivalent public methods are exposed on api29+ directly on the native widget + if (sdkVersion() < 29) { + this._selectorWheelPaint = getSelectorWheelPaint(nativeView); + } + const formatter = new Formatter(this); nativeView.setFormatter(formatter); (nativeView).formatter = formatter; @@ -153,28 +164,33 @@ export class ListPicker extends ListPickerBase { selectedIndexProperty.coerce(this); } - [colorProperty.getDefault](): { wheelColor: number, textColor: number } { - const editText = (this.nativeViewProtected).editText; - - return { - wheelColor: this._selectorWheelPaint.getColor(), - textColor: editText ? editText.getTextColors().getDefaultColor() : -1 - }; - } - [colorProperty.setNative](value: { wheelColor: number, textColor: number } | Color) { - let color: number; - let wheelColor: number; - if (value instanceof Color) { - color = wheelColor = value.android; - } else { - color = value.textColor; - wheelColor = value.wheelColor; + [colorProperty.getDefault](): number { + // api28 and lower uses reflection to retrieve and manipulate + // android.graphics.Paint object; this is no longer allowed on newer api levels but + // equivalent public methods are exposed on api29+ directly on the native widget + if (this._selectorWheelPaint) { + return this._selectorWheelPaint.getColor(); } - this._selectorWheelPaint.setColor(wheelColor); - const editText = (this.nativeViewProtected).editText; - if (editText) { - editText.setTextColor(color); + return this.nativeView.getTextColor(); + } + [colorProperty.setNative](value: number | Color) { + const color = value instanceof Color ? value.android : value; + + // api28 and lower uses reflection to retrieve and manipulate + // android.graphics.Paint object; this is no longer allowed on newer api levels but + // equivalent public methods are exposed on api29+ directly on the native widget + if (this._selectorWheelPaint) { + this._selectorWheelPaint.setColor(color); + + const editText = (this.nativeViewProtected).editText; + if (editText) { + editText.setTextColor(color); + } + } else { + // api29 and higher native implementation sets + // both wheel color and input text color with single call + this.nativeView.setTextColor(color); } } } diff --git a/tns-core-modules/ui/tabs/tabs.android.ts b/tns-core-modules/ui/tabs/tabs.android.ts index c2334f859..d5cfbf212 100644 --- a/tns-core-modules/ui/tabs/tabs.android.ts +++ b/tns-core-modules/ui/tabs/tabs.android.ts @@ -615,23 +615,15 @@ export class Tabs extends TabsBase { // ICON const iconSource = tabStripItem.image && tabStripItem.image.src; if (iconSource) { - if (iconSource.indexOf(RESOURCE_PREFIX) === 0) { - tabItemSpec.iconId = ad.resources.getDrawableId(iconSource.substr(RESOURCE_PREFIX.length)); - if (tabItemSpec.iconId === 0) { - // TODO: - // traceMissingIcon(iconSource); - } - } else { - const icon = this.getIcon(tabStripItem); + const icon = this.getIcon(tabStripItem); - if (icon) { - // TODO: Make this native call that accepts string so that we don't load Bitmap in JS. - // tslint:disable-next-line:deprecation - tabItemSpec.iconDrawable = icon; - } else { - // TODO: - // traceMissingIcon(iconSource); - } + if (icon) { + // TODO: Make this native call that accepts string so that we don't load Bitmap in JS. + // tslint:disable-next-line:deprecation + tabItemSpec.iconDrawable = icon; + } else { + // TODO: + // traceMissingIcon(iconSource); } } } diff --git a/tns-core-modules/ui/tabs/tabs.ios.ts b/tns-core-modules/ui/tabs/tabs.ios.ts index 4a664cb1a..be26ca1b0 100644 --- a/tns-core-modules/ui/tabs/tabs.ios.ts +++ b/tns-core-modules/ui/tabs/tabs.ios.ts @@ -82,26 +82,24 @@ class UIPageViewControllerImpl extends UIPageViewController { public viewDidLoad(): void { const owner = this._owner.get(); - if (owner.tabStrip) { - const tabBarItems = owner.tabBarItems; - const tabBar = MDCTabBar.alloc().initWithFrame(this.view.bounds); + const tabBarItems = owner.tabBarItems; + const tabBar = MDCTabBar.alloc().initWithFrame(this.view.bounds); - if (tabBarItems && tabBarItems.length) { - tabBar.items = NSArray.arrayWithArray(tabBarItems); - } - - tabBar.delegate = this.tabBarDelegate = MDCTabBarDelegateImpl.initWithOwner(new WeakRef(owner)); - tabBar.tintColor = UIColor.blueColor; - tabBar.barTintColor = UIColor.whiteColor; - tabBar.setTitleColorForState(UIColor.blackColor, MDCTabBarItemState.Normal); - tabBar.setTitleColorForState(UIColor.blackColor, MDCTabBarItemState.Selected); - tabBar.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleBottomMargin; - tabBar.alignment = MDCTabBarAlignment.Leading; - tabBar.sizeToFit(); - - this.tabBar = tabBar; - this.view.addSubview(tabBar); + if (tabBarItems && tabBarItems.length) { + tabBar.items = NSArray.arrayWithArray(tabBarItems); } + + tabBar.delegate = this.tabBarDelegate = MDCTabBarDelegateImpl.initWithOwner(new WeakRef(owner)); + tabBar.tintColor = UIColor.blueColor; + tabBar.barTintColor = UIColor.whiteColor; + tabBar.setTitleColorForState(UIColor.blackColor, MDCTabBarItemState.Normal); + tabBar.setTitleColorForState(UIColor.blackColor, MDCTabBarItemState.Selected); + tabBar.autoresizingMask = UIViewAutoresizing.FlexibleWidth | UIViewAutoresizing.FlexibleBottomMargin; + tabBar.alignment = MDCTabBarAlignment.Leading; + tabBar.sizeToFit(); + + this.tabBar = tabBar; + this.view.addSubview(tabBar); } public viewWillAppear(animated: boolean): void { @@ -152,13 +150,22 @@ class UIPageViewControllerImpl extends UIPageViewController { scrollViewHeight = this.view.frame.size.height - safeAreaInsetsBottom; } - const parent = owner.parent; + let parent = owner.parent; + + // Handle Angular scenario where Tabs is in a ProxyViewContainer + // It is possible to wrap components in ProxyViewContainers indefinitely + while (parent && !parent.nativeViewProtected) { + parent = parent.parent; + } + if (parent && majorVersion > 10) { // TODO: Figure out a better way to handle ViewController nesting/Safe Area nesting - tabBarTop = Math.max(tabBarTop, owner.parent.nativeView.safeAreaInsets.top); + tabBarTop = Math.max(tabBarTop, parent.nativeView.safeAreaInsets.top); } this.tabBar.frame = CGRectMake(0, tabBarTop, this.tabBar.frame.size.width, tabBarHeight); + } else { + this.tabBar.hidden = true; } const subViews: NSArray = this.view.subviews; @@ -885,6 +892,7 @@ export class Tabs extends TabsBase { } private getIconRenderingMode(): UIImageRenderingMode { + // MDCTabBar doesn't work with rendering mode AlwaysTemplate return UIImageRenderingMode.AlwaysOriginal; } diff --git a/tns-core-modules/ui/utils.android.ts b/tns-core-modules/ui/utils.android.ts index b253eba9e..b8e7bc80b 100644 --- a/tns-core-modules/ui/utils.android.ts +++ b/tns-core-modules/ui/utils.android.ts @@ -10,4 +10,4 @@ export function _layoutRootView(rootView: any, parentBounds: any) { throw new Error("Not implemented for Android"); } -} \ No newline at end of file +} diff --git a/tns-core-modules/ui/utils.d.ts b/tns-core-modules/ui/utils.d.ts index e54e208bd..a30b9f6f3 100644 --- a/tns-core-modules/ui/utils.d.ts +++ b/tns-core-modules/ui/utils.d.ts @@ -3,6 +3,7 @@ */ import { View } from "./core/view"; + export module ios { /** * Gets actual height of a [UIView](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIView_Class/) widget in device pixels. diff --git a/tns-core-modules/ui/utils.ios.ts b/tns-core-modules/ui/utils.ios.ts index 21ed98575..de61713bb 100644 --- a/tns-core-modules/ui/utils.ios.ts +++ b/tns-core-modules/ui/utils.ios.ts @@ -24,4 +24,4 @@ export module ios { return utils.layout.toDevicePixels(min); } -} \ No newline at end of file +} From 570c17f41a2fdfee1bc675812b39f8a05138e68b Mon Sep 17 00:00:00 2001 From: Ryan Pendergast Date: Thu, 12 Sep 2019 07:54:02 -0500 Subject: [PATCH 07/11] chore: dev-tsc-all target invalid in package.json (#7746) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3c57d4ab9..0a6153892 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ "dev-tsc-tests": "npm run tsc -- -p tests", "dev-tsc-apps": "npm run tsc -- -p apps", "dev-tsc-e2e": "npm run tsc -- -p e2e", - "dev-tsc-all": "npm run dev-tsc-tns-platform-declarations && npm run tsc && npm run dev-tsc-tests && npm run dev-tsc-apps && && npm run dev-tsc-e2e", + "dev-tsc-all": "npm run dev-tsc-tns-platform-declarations && npm run tsc && npm run dev-tsc-tests && npm run dev-tsc-apps && npm run dev-tsc-e2e", "dev-link-tns-core-modules-widgets": "(cd tns-core-modules-widgets/dist/package && npm link) && (cd tns-core-modules && npm i ../tns-core-modules-widgets/dist/package --save)", "dev-declarations": "npm run setup && rm -rf tns-platform-declarations/ios/objc* && TNS_TYPESCRIPT_DECLARATIONS_PATH=$PWD/tns-platform-declarations/ios/objc tns build ios --path tests", "test": "npm run test-android && npm run test-ios", From f438ad7d69b7d3f845b331afecb819bbd14518c7 Mon Sep 17 00:00:00 2001 From: milind soorya <36722289+milindsoorya@users.noreply.github.com> Date: Thu, 12 Sep 2019 18:24:34 +0530 Subject: [PATCH 08/11] chore: fix typo (#7765) --- tests/app/application/application-tests.android.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/app/application/application-tests.android.ts b/tests/app/application/application-tests.android.ts index 1c76429fe..7cf181f81 100644 --- a/tests/app/application/application-tests.android.ts +++ b/tests/app/application/application-tests.android.ts @@ -41,7 +41,7 @@ export function testAndroidApplicationInitialized() { TKUnit.assert(app.android, "Android application not initialized."); TKUnit.assert(app.android.context, "Android context not initialized."); TKUnit.assert(app.android.foregroundActivity, "Android foregroundActivity not initialized."); - TKUnit.assert(app.android.foregroundActivity.isNativeScriptActivity, "Andorid foregroundActivity.isNativeScriptActivity is false."); + TKUnit.assert(app.android.foregroundActivity.isNativeScriptActivity, "Android foregroundActivity.isNativeScriptActivity is false."); TKUnit.assert(app.android.startActivity, "Android startActivity not initialized."); TKUnit.assert(app.android.nativeApp, "Android nativeApp not initialized."); TKUnit.assert(app.android.orientation, "Android orientation not initialized."); From 3cabdde05f9f36c6939aa3cb0243e8b92594e86c Mon Sep 17 00:00:00 2001 From: "Bundyo (Kamen Bundev)" Date: Fri, 13 Sep 2019 13:49:35 +0300 Subject: [PATCH 09/11] feat(css): Add HSL/HSLA support (#7730) --- tns-core-modules/color/color-common.ts | 50 ++++++++++++++---- tns-core-modules/css/parser.ts | 70 +++++++++++++++++++++++++- unit-tests/css/parser.ts | 6 ++- 3 files changed, 111 insertions(+), 15 deletions(-) diff --git a/tns-core-modules/color/color-common.ts b/tns-core-modules/color/color-common.ts index b0b149253..b33e63e63 100644 --- a/tns-core-modules/color/color-common.ts +++ b/tns-core-modules/color/color-common.ts @@ -1,6 +1,7 @@ -import * as definition from "."; +import * as definition from "."; import * as types from "../utils/types"; import * as knownColors from "./known-colors"; +import { convertHSLToRGBColor } from "tns-core-modules/css/parser"; const SHARP = "#"; const HEX_REGEX = /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)|(^#[0-9A-F]{8}$)/i; @@ -18,6 +19,8 @@ export class Color implements definition.Color { if (types.isString(arg)) { if (isRgbOrRgba(arg)) { this._argb = argbFromRgbOrRgba(arg); + } else if (isHslOrHsla(arg)) { + this._argb = argbFromHslOrHsla(arg); } else if (knownColors.isKnownName(arg)) { // The parameter is a known color name const hex = knownColors.getKnownColor(arg); @@ -127,7 +130,7 @@ export class Color implements definition.Color { return true; } - return HEX_REGEX.test(value) || isRgbOrRgba(value); + return HEX_REGEX.test(value) || isRgbOrRgba(value) || isHslOrHsla(value); } private _componentToHex(component: number): string { @@ -162,33 +165,58 @@ function isRgbOrRgba(value: string): boolean { return (toLower.indexOf("rgb(") === 0 || toLower.indexOf("rgba(") === 0) && toLower.indexOf(")") === (toLower.length - 1); } -function argbFromRgbOrRgba(value: string): number { +function isHslOrHsla(value: string): boolean { const toLower = value.toLowerCase(); - const parts = toLower.replace("rgba(", "").replace("rgb(", "").replace(")", "").trim().split(","); - let r = 255; - let g = 255; - let b = 255; + return (toLower.indexOf("hsl(") === 0 || toLower.indexOf("hsla(") === 0) && toLower.indexOf(")") === (toLower.length - 1); +} + +function parseColorWithAlpha(value: string): any { + const toLower = value.toLowerCase(); + const parts = toLower.replace(/(rgb|hsl)a?\(/, "") + .replace(")", "") + .trim().split(","); + + let f = 255; + let s = 255; + let t = 255; let a = 255; if (parts[0]) { - r = parseInt(parts[0].trim()); + f = parseInt(parts[0].trim()); } if (parts[1]) { - g = parseInt(parts[1].trim()); + s = parseInt(parts[1].trim()); } if (parts[2]) { - b = parseInt(parts[2].trim()); + t = parseInt(parts[2].trim()); } if (parts[3]) { a = Math.round(parseFloat(parts[3].trim()) * 255); } + return { f, s, t, a }; +} + +function argbFromRgbOrRgba(value: string): number { + const { f: r, s: g, t: b, a } = parseColorWithAlpha(value); + return (a & 0xFF) * 0x01000000 + (r & 0xFF) * 0x00010000 + (g & 0xFF) * 0x00000100 - + (b & 0xFF) * 0x00000001; + + (b & 0xFF); +} + +function argbFromHslOrHsla(value: string): number { + const { f: h, s: s, t: l, a } = parseColorWithAlpha(value); + + const { r, g, b } = convertHSLToRGBColor(h, s, l); + + return (a & 0xFF) * 0x01000000 + + (r & 0xFF) * 0x00010000 + + (g & 0xFF) * 0x00000100 + + (b & 0xFF); } diff --git a/tns-core-modules/css/parser.ts b/tns-core-modules/css/parser.ts index 28d464209..1ab2a7823 100644 --- a/tns-core-modules/css/parser.ts +++ b/tns-core-modules/css/parser.ts @@ -84,7 +84,7 @@ export function parseHexColor(text: string, start: number = 0): Parsed { function rgbaToArgbNumber(r: number, g: number, b: number, a: number = 1): number | undefined { if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255 && a >= 0 && a <= 1) { - return (Math.round(a * 0xFF) * 0x01000000) + (r * 0x010000) + (g * 0x000100) + (b * 0x000001); + return (Math.round(a * 0xFF) * 0x01000000) + (r * 0x010000) + (g * 0x000100) + b; } else { return null; } @@ -116,6 +116,67 @@ export function parseRGBAColor(text: string, start: number = 0): Parsed { return { start, end, value }; } +export function convertHSLToRGBColor(hue: number, saturation: number, lightness: number): { r: number; g: number; b: number; } { + // Per formula it will be easier if hue is divided to 60° and saturation to 100 beforehand + // https://en.wikipedia.org/wiki/HSL_and_HSV#HSL_to_RGB + hue /= 60; + lightness /= 100; + + let chroma = (1 - Math.abs(2 * lightness - 1)) * saturation / 100, + X = chroma * (1 - Math.abs(hue % 2 - 1)), + // Add lightness match to all RGB components beforehand + { m: r, m: g, m: b } = { m: lightness - chroma / 2 }; + + if (0 <= hue && hue < 1) { r += chroma; g += X; } + else if (hue < 2) { r += X; g += chroma; } + else if (hue < 3) { g += chroma; b += X; } + else if (hue < 4) { g += X; b += chroma; } + else if (hue < 5) { r += X; b += chroma; } + else if (hue < 6) { r += chroma; b += X; } + + return { + r: Math.round(r * 0xFF), + g: Math.round(g * 0xFF), + b: Math.round(b * 0xFF) + }; +} + +function hslaToArgbNumber(h: number, s: number, l: number, a: number = 1): number | undefined { + let { r, g, b } = convertHSLToRGBColor(h, s, l); + + if (r >= 0 && r <= 255 && g >= 0 && g <= 255 && b >= 0 && b <= 255 && a >= 0 && a <= 1) { + return (Math.round(a * 0xFF) * 0x01000000) + (r * 0x010000) + (g * 0x000100) + b; + } else { + return null; + } +} + +const hslColorRegEx = /\s*(hsl\(\s*([\d.]*)\s*,\s*([\d.]*)%\s*,\s*([\d.]*)%\s*\))/gy; +export function parseHSLColor(text: string, start: number = 0): Parsed { + hslColorRegEx.lastIndex = start; + const result = hslColorRegEx.exec(text); + if (!result) { + return null; + } + const end = hslColorRegEx.lastIndex; + const value = result[1] && hslaToArgbNumber(parseFloat(result[2]), parseFloat(result[3]), parseFloat(result[4])); + + return { start, end, value }; +} + +const hslaColorRegEx = /\s*(hsla\(\s*([\d.]*)\s*,\s*([\d.]*)%\s*,\s*([\d.]*)%\s*,\s*([01]?\.?\d*)\s*\))/gy; +export function parseHSLAColor(text: string, start: number = 0): Parsed { + hslaColorRegEx.lastIndex = start; + const result = hslaColorRegEx.exec(text); + if (!result) { + return null; + } + const end = hslaColorRegEx.lastIndex; + const value = hslaToArgbNumber(parseFloat(result[2]), parseFloat(result[3]), parseFloat(result[4]), parseFloat(result[5])); + + return { start, end, value }; +} + export enum colors { transparent = 0x00000000, aliceblue = 0xFFF0F8FF, @@ -280,7 +341,12 @@ export function parseColorKeyword(value, start: number, keyword = parseKeyword(v } export function parseColor(value: string, start: number = 0, keyword = parseKeyword(value, start)): Parsed { - return parseHexColor(value, start) || parseColorKeyword(value, start, keyword) || parseRGBColor(value, start) || parseRGBAColor(value, start); + return parseHexColor(value, start) || + parseColorKeyword(value, start, keyword) || + parseRGBColor(value, start) || + parseRGBAColor(value, start) || + parseHSLColor(value, start) || + parseHSLAColor(value, start); } const keywordRegEx = /\s*([a-z][\w\-]*)\s*/giy; diff --git a/unit-tests/css/parser.ts b/unit-tests/css/parser.ts index 667f12177..fa21ed04d 100644 --- a/unit-tests/css/parser.ts +++ b/unit-tests/css/parser.ts @@ -56,6 +56,8 @@ describe("css", () => { test(parseColor, " #85456789 ", { start: 0, end: 12, value: 0x85456789 }); test(parseColor, " rgb(255, 8, 128) ", { start: 0, end: 18, value: 0xFFFF0880 }); test(parseColor, " rgba(255, 8, 128, 0.5) ", { start: 0, end: 24, value: 0x80FF0880 }); + test(parseColor, " hsl(330.9, 100%, 51.6%) ", { start: 0, end: 25, value: 0xFFFF0880 }); + test(parseColor, " hsla(330.9, 100%, 51.6%, 0.5) ", { start: 0, end: 31, value: 0x80FF0880 }); test(parseColor, "#FF0000 url(lucky.gif)", 8, null); test(parseColor, "url(lucky.gif) #FF0000 repeat", 15, { start: 15, end: 23, value: 0xFFFF0000 }); }); @@ -175,11 +177,11 @@ describe("css", () => { test(parseSelector, `[src ${attributeTest} "val"]`, { start: 0, end: 12 + attributeTest.length, value: [[[{ type: "[]", property: "src", test: attributeTest, value: "val"}], undefined]]}); }); test(parseSelector, "listview > .image", { start: 0, end: 17, value: [ - [[{ type: "", identifier: "listview"}], ">"], + [[{ type: "", identifier: "listview"}], ">"], [[{ type: ".", identifier: "image"}], undefined] ]}); test(parseSelector, "listview .image", { start: 0, end: 16, value: [ - [[{ type: "", identifier: "listview"}], " "], + [[{ type: "", identifier: "listview"}], " "], [[{ type: ".", identifier: "image"}], undefined] ]}); test(parseSelector, "button:hover", { start: 0, end: 12, value: [[[{ type: "", identifier: "button" }, { type: ":", identifier: "hover"}], undefined]]}); From 0b3ceb0e7c4c6ed5222b61885fe66481de7a5a1e Mon Sep 17 00:00:00 2001 From: Manol Donev Date: Fri, 13 Sep 2019 14:53:10 +0300 Subject: [PATCH 10/11] chore: update dev workflow (#7819) --- DevelopmentWorkflow.md | 79 +++++++++++++----------------------------- 1 file changed, 25 insertions(+), 54 deletions(-) diff --git a/DevelopmentWorkflow.md b/DevelopmentWorkflow.md index 6e8f810b3..0f642077d 100644 --- a/DevelopmentWorkflow.md +++ b/DevelopmentWorkflow.md @@ -4,11 +4,12 @@ Development Workflow ## Project Structure The repository contains several packages and apps: - - `tns-core-modules` - The core NativeScript TypeScript modules used to develop NativeScript apps. - - `apps` - UI app used for manual testing and automation. - - `e2e` - applications and *e2e* tests. - - `tests` - Unit tests app for the `tns-core-modules`. - - `tns-platform-declarations` - TypeScript definitions for Android and iOS native APIs. + - `tns-core-modules` - The core NativeScript TypeScript modules used to develop NativeScript apps + - `tns-core-modules-widgets` - The native widgets (Java and Objective-C) used by the core NativeScript modules + - `e2e/ui-tests-app` - UI app used for manual testing and automation + - `e2e` - applications and *e2e* tests + - `tests` - Unit tests app for the `tns-core-modules` + - `tns-platform-declarations` - TypeScript definitions for Android and iOS native APIs Working with the repo is organized with npm scripts, go and read through the `scripts` section in the [package.json](./package.json). @@ -16,7 +17,7 @@ go and read through the `scripts` section in the [package.json](./package.json). Managing dependencies: - `tns-core-modules` depends on: - `tns-platform-declarations` - - `apps` depends on: + - `e2e/ui-tests-app` depends on: - `tns-platform-declarations` - `tns-core-modules` - `e2e` depends on: @@ -26,71 +27,44 @@ Managing dependencies: - `tns-core-modules` > NOTE: `tns-core-modules` depends on `tns-core-modules-widgets`, -this dependency contains native code and is rarely modified so for now it remains outside this repo. ## Initial Setup Clone (or fork/clone) the repo: -```bash +``` bash git clone https://github.com/NativeScript/NativeScript.git ``` -Install devDependencies: +Install dependencies: -```bash +``` bash npm install ``` - - ## Running Unit Tests -``` -cd ./tests -tns run android| ios +``` bash +cd tests +tns run android | ios ``` -## Running the Test App +## Running the UI Test App -The test app is an ordinary NativeScript app that logs the test results as it go. +The UI test app is an ordinary NativeScript app that logs the test results on the go. After the [initial setup](#initial-setup) you can run the tests with: -``` -# Make sure TypeScript is transpiled -tsc +``` bash +cd e2e/ui-tests-app + +# Run the Android app +tns platform add android@next # NOTE: do not commit this change to package.json +tns run android + +# Run the iOS app +tns platform add ios@next # NOTE: do not commit this change to package.json +tns run ios -# Run the app -tns run ios --path apps -tns run android --path apps ``` ## Running Another App @@ -107,9 +81,6 @@ tns run ios tns run android ``` -> Note: You still have to rebuild the TypeScript if you have made changes in the code of the core-modules. - - ## Platform declarations To update the platform declarations (the ios.d.ts-es) you can run: From 4f421ffbfea9914665527c52f476510c748240f0 Mon Sep 17 00:00:00 2001 From: Yurii Cherniavskyi Date: Fri, 13 Sep 2019 19:02:37 +0300 Subject: [PATCH 11/11] fix(application-settings-android): possible uninitialized sharedPreferences variable usage (#7813) --- .../application-settings/application-settings.android.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tns-core-modules/application-settings/application-settings.android.ts b/tns-core-modules/application-settings/application-settings.android.ts index c042208c5..aaa09074e 100644 --- a/tns-core-modules/application-settings/application-settings.android.ts +++ b/tns-core-modules/application-settings/application-settings.android.ts @@ -85,10 +85,13 @@ export function clear(): void { } export function flush(): boolean { + ensureSharedPreferences(); + return sharedPreferences.edit().commit(); } export function getAllKeys(): Array { + ensureSharedPreferences(); const mappedPreferences = sharedPreferences.getAll(); const iterator = mappedPreferences.keySet().iterator(); const result = [];