mirror of
https://github.com/NativeScript/NativeScript.git
synced 2025-11-05 13:26:48 +08:00
Merge branch 'master' into animate-width-height
This commit is contained in:
27
CHANGELOG.md
27
CHANGELOG.md
@@ -1,3 +1,30 @@
|
||||
<a name="5.4.0"></a>
|
||||
# [5.4.0](https://github.com/NativeScript/NativeScript/compare/5.3.2...5.4.0) (2019-05-14)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* throw if failed to load component ([#7186](https://github.com/NativeScript/NativeScript/issues/7186)) ([b7abb3d](https://github.com/NativeScript/NativeScript/commit/b7abb3d))
|
||||
* **android/button:** possible incorrect button visual state ([#7190](https://github.com/NativeScript/NativeScript/issues/7190)) ([2a02360](https://github.com/NativeScript/NativeScript/commit/2a02360))
|
||||
* **devtools-ios:** Ensure UI modifications run on main thread ([c60f74d](https://github.com/NativeScript/NativeScript/commit/c60f74d)), closes [#7219](https://github.com/NativeScript/NativeScript/issues/7219)
|
||||
* **ios:** add null check to TouchGestureRecognizer ([#7182](https://github.com/NativeScript/NativeScript/issues/7182)) ([7d3f0d9](https://github.com/NativeScript/NativeScript/commit/7d3f0d9))
|
||||
* **ios:** application.displayedEvent does not depend on trace to fire ([#7141](https://github.com/NativeScript/NativeScript/issues/7141)) ([#7156](https://github.com/NativeScript/NativeScript/issues/7156)) ([4e56c89](https://github.com/NativeScript/NativeScript/commit/4e56c89))
|
||||
* **ios:** image cache module not longer sets null in NSCache ([#7171](https://github.com/NativeScript/NativeScript/issues/7171)) ([4f79d2e](https://github.com/NativeScript/NativeScript/commit/4f79d2e))
|
||||
* **ios-modal:** closeCallback not being called with popover presentation style ([#7189](https://github.com/NativeScript/NativeScript/issues/7189)) ([aa44eb9](https://github.com/NativeScript/NativeScript/commit/aa44eb9))
|
||||
* **ios-tabview:** crash when setting tab text color ([#7188](https://github.com/NativeScript/NativeScript/issues/7188)) ([77c45da](https://github.com/NativeScript/NativeScript/commit/77c45da))
|
||||
* **text:** crash when removing FormattedText ([#7237](https://github.com/NativeScript/NativeScript/issues/7237)) ([37b53c6](https://github.com/NativeScript/NativeScript/commit/37b53c6))
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* **android:** elevation shadow support ([#7136](https://github.com/NativeScript/NativeScript/issues/7136)) ([cf533a7](https://github.com/NativeScript/NativeScript/commit/cf533a7))
|
||||
* **android:** implement a 'activityNewIntent' event ([3efc06e](https://github.com/NativeScript/NativeScript/commit/3efc06e))
|
||||
* **android:** implement BorderDrawable outline ([ec07a99](https://github.com/NativeScript/NativeScript/commit/ec07a99))
|
||||
* **hmr:** preserve navigation history on applying changes ([#7146](https://github.com/NativeScript/NativeScript/issues/7146)) ([d35e14e](https://github.com/NativeScript/NativeScript/commit/d35e14e))
|
||||
* **switch:** add property for off state background color ([#7138](https://github.com/NativeScript/NativeScript/issues/7138)) ([f0146f0](https://github.com/NativeScript/NativeScript/commit/f0146f0))
|
||||
|
||||
|
||||
|
||||
## [5.3.2](https://github.com/NativeScript/NativeScript/compare/5.3.1...5.3.2) (2019-05-03)
|
||||
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ Button {
|
||||
}
|
||||
|
||||
#s10 {
|
||||
border-width: 5 0; border-color: black; background-color: white;
|
||||
android-elevation: 0; border-width: 5 0; border-color: black;
|
||||
}
|
||||
|
||||
#s11 {
|
||||
|
||||
43
apps/app/ui-tests-app/css/elevation.css
Normal file
43
apps/app/ui-tests-app/css/elevation.css
Normal file
@@ -0,0 +1,43 @@
|
||||
Label, Button {
|
||||
text-align: center;
|
||||
padding: 10;
|
||||
margin: 16;
|
||||
background-color: #bbb;
|
||||
}
|
||||
|
||||
.elevation-0 {
|
||||
android-elevation: 0;
|
||||
}
|
||||
|
||||
.elevation-2 {
|
||||
android-elevation: 2;
|
||||
}
|
||||
|
||||
.elevation-4 {
|
||||
android-elevation: 4;
|
||||
}
|
||||
|
||||
.elevation-4:highlighted {
|
||||
android-elevation: 2;
|
||||
}
|
||||
|
||||
.elevation-8 {
|
||||
android-elevation: 8;
|
||||
}
|
||||
|
||||
.elevation-10 {
|
||||
android-elevation: 10;
|
||||
}
|
||||
|
||||
.pressed-z-10 {
|
||||
android-dynamic-elevation-offset: 10;
|
||||
}
|
||||
|
||||
.round {
|
||||
color: #fff;
|
||||
background-color: #ff1744;
|
||||
border-radius: 50%; /* TODO kills elevation */
|
||||
width: 80;
|
||||
height: 80;
|
||||
android-elevation: 8;
|
||||
}
|
||||
20
apps/app/ui-tests-app/css/elevation.ts
Normal file
20
apps/app/ui-tests-app/css/elevation.ts
Normal file
@@ -0,0 +1,20 @@
|
||||
import { Button } from "tns-core-modules/ui/button/button";
|
||||
import { EventData } from "tns-core-modules/ui/page/page";
|
||||
|
||||
const states = [
|
||||
{ class: "", text: "default elevation" },
|
||||
{ class: "elevation-10", text: "elevetion 10" },
|
||||
{ class: "elevation-10 pressed-z-10", text: "elevetion 10 pressed-z 10" },
|
||||
{ class: "elevation-0", text: "elevetion 0" },
|
||||
]
|
||||
let currentState = 0;
|
||||
|
||||
export function buttonTap(args: EventData) {
|
||||
let btn: Button = args.object as Button;
|
||||
currentState++;
|
||||
if (currentState >= states.length) {
|
||||
currentState = 0;
|
||||
}
|
||||
btn.className = states[currentState].class;
|
||||
btn.text = states[currentState].text;
|
||||
}
|
||||
25
apps/app/ui-tests-app/css/elevation.xml
Normal file
25
apps/app/ui-tests-app/css/elevation.xml
Normal file
@@ -0,0 +1,25 @@
|
||||
<Page xmlns="http://schemas.nativescript.org/tns.xsd" loaded="onLoaded">
|
||||
<ScrollView>
|
||||
<StackLayout backgroundColor="aliceblue" androidElevation="2" padding="10" margin="20">
|
||||
<Button text="default elevation" tap="buttonTap"/>
|
||||
|
||||
<Button class="elevation-0" text="elevation 0"/>
|
||||
|
||||
<Label class="elevation-2" text="Label with elevation 2"/>
|
||||
|
||||
<StackLayout androidElevation="4" backgroundColor="#ff1744" horizontalAlignment="center" margin="20">
|
||||
<Button class="elevation-2" text="elevation 2"/>
|
||||
<Button class="elevation-4" text="elevation 4"/>
|
||||
</StackLayout>
|
||||
|
||||
<StackLayout orientation="horizontal" horizontalAlignment="center">
|
||||
<Button class="round" androidElevation="4" text="el. 4"/>
|
||||
<Button class="elevation-8 round" text="el. 8"/>
|
||||
</StackLayout>
|
||||
|
||||
<Label class="elevation-8" text="elevation 8"/>
|
||||
<Button class="elevation-8" text="elevation 8, with radius" borderRadius="4"/>
|
||||
<Button class="elevation-10" text="elevation 10"/>
|
||||
</StackLayout>
|
||||
</ScrollView>
|
||||
</Page>
|
||||
@@ -38,6 +38,7 @@ export function loadExamples() {
|
||||
examples.set("margins-paddings-with-percentage", "css/margins-paddings-with-percentage");
|
||||
examples.set("padding-and-border", "css/padding-and-border");
|
||||
examples.set("combinators", "css/combinators");
|
||||
examples.set("elevation", "css/elevation");
|
||||
examples.set("styled-formatted-text", "css/styled-formatted-text");
|
||||
examples.set("non-uniform-radius", "css/non-uniform-radius");
|
||||
examples.set("missing-background-image", "css/missing-background-image");
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<Label text="pixels" />
|
||||
<StackLayout borderWidth="1px" borderColor="black" horizontalAlignment="left" verticalAlignment="top" orientation="horizontal" padding="1px">
|
||||
<Label text="Label" borderWidth="1px" borderRadius="10px" borderColor="green" padding="1px" margin="1px" />
|
||||
<Button text="Button" borderWidth="1px" borderRadius="10px" borderColor="green" padding="1px" margin="1px" backgroundColor="orange" />
|
||||
<Button text="Button" borderWidth="1px" borderRadius="10px" borderColor="green" padding="1px" margin="1px" androidElevation="0" />
|
||||
<TextView text="Text View" borderWidth="1px" borderRadius="10px" borderColor="green" padding="1px" margin="1px" />
|
||||
<TextField text="Text Field" borderWidth="1px" borderRadius="10px" borderColor="green" padding="1px" margin="1px" />
|
||||
<Image src="~/ui-tests-app/resources/images/gravatar.png" borderWidth="1px" borderRadius="10px" borderColor="green" padding="1px" margin="1px" />
|
||||
@@ -12,7 +12,7 @@
|
||||
|
||||
<StackLayout borderWidth="2px" borderColor="green" orientation="horizontal" padding="2px">
|
||||
<Label text="Label" borderWidth="5px" borderRadius="10px" borderColor="black" padding="5px" margin="5px" />
|
||||
<Button text="Button" borderWidth="4px" borderRadius="10px" borderColor="black" padding="4px" margin="4px" backgroundColor="orange" />
|
||||
<Button text="Button" borderWidth="4px" borderRadius="10px" borderColor="black" padding="4px" margin="4px" androidElevation="0" />
|
||||
<TextView text="Text View" borderWidth="3px" borderRadius="10px" borderColor="black" padding="3px" margin="3px" />
|
||||
<TextField text="Text Field" borderWidth="2px" borderRadius="10px" borderColor="black" padding="2px" margin="2px" />
|
||||
</StackLayout>
|
||||
@@ -32,7 +32,7 @@
|
||||
<Label text="device independent pixels" />
|
||||
<StackLayout borderWidth="1" borderColor="black" horizontalAlignment="left" verticalAlignment="top" orientation="horizontal" padding="1">
|
||||
<Label text="Label" borderWidth="1" borderRadius="10" borderColor="green" padding="1" margin="1" />
|
||||
<Button text="Button" borderWidth="1" borderRadius="10" borderColor="green" padding="1" margin="1" backgroundColor="orange" />
|
||||
<Button text="Button" borderWidth="1" borderRadius="10" borderColor="green" padding="1" margin="1" androidElevation="0" />
|
||||
<TextView text="Text View" borderWidth="1" borderRadius="10" borderColor="green" padding="1" margin="1" />
|
||||
<TextField text="Text Field" borderWidth="1" borderRadius="10" borderColor="green" padding="1" margin="1" />
|
||||
<Image src="~/ui-tests-app/resources/images/gravatar.png" borderWidth="1" borderRadius="10" borderColor="green" padding="1" margin="1" />
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
<StackLayout borderWidth="2" borderColor="green" orientation="horizontal" padding="2">
|
||||
<Label text="Label" borderWidth="5" borderRadius="10" borderColor="black" padding="5" margin="5" />
|
||||
<Button text="Button" borderWidth="4" borderRadius="10" borderColor="black" padding="4" margin="4" backgroundColor="orange" />
|
||||
<Button text="Button" borderWidth="4" borderRadius="10" borderColor="black" padding="4" margin="4" androidElevation="0" />
|
||||
<TextView text="Text View" borderWidth="3" borderRadius="10" borderColor="black" padding="3" margin="3" />
|
||||
<TextField text="Text Field" borderWidth="2" borderRadius="10" borderColor="black" padding="2" margin="2" />
|
||||
</StackLayout>
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
border-color: gray;
|
||||
}
|
||||
.control Button {
|
||||
android-elevation: 0;
|
||||
border-width: 1 1 0 0;
|
||||
border-color: gray;
|
||||
background-color: white;
|
||||
font-size: 9;
|
||||
padding: 0;
|
||||
height: 0;
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
#button1 {
|
||||
border-color: transparent;
|
||||
android-elevation: 0;
|
||||
border-color: rgba(0, 0, 0, 0);
|
||||
border-width: 3;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
#button2 {
|
||||
android-elevation: 0;
|
||||
border-color: rgba(0, 0, 0, 0.5);
|
||||
border-width: 3;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
#button3 {
|
||||
android-elevation: 0;
|
||||
border-width: 3;
|
||||
background-color: white;
|
||||
}
|
||||
@@ -27,5 +27,6 @@ export function loadExamples() {
|
||||
examples.set("tab-view-tab-text-font-size", "tab-view/tab-view-tab-text-font-size");
|
||||
examples.set("tab-view-android-swipe", "tab-view/tab-view-android-swipe");
|
||||
examples.set("tab-view-icon-title-placement", "tab-view/icon-title-placement");
|
||||
examples.set("tab-text-color", "tab-view/tab-text-color");
|
||||
return examples;
|
||||
}
|
||||
|
||||
24
apps/app/ui-tests-app/tab-view/tab-text-color.xml
Normal file
24
apps/app/ui-tests-app/tab-view/tab-text-color.xml
Normal file
@@ -0,0 +1,24 @@
|
||||
<Page>
|
||||
<TabView tabTextColor="red">
|
||||
<TabView.items>
|
||||
|
||||
<TabViewItem title="Tab 1">
|
||||
<TabViewItem.view>
|
||||
<Label text="Label 1" />
|
||||
</TabViewItem.view>
|
||||
</TabViewItem>
|
||||
|
||||
<TabViewItem title="Tab 2">
|
||||
<TabViewItem.view>
|
||||
<Label text="Label 2" />
|
||||
</TabViewItem.view>
|
||||
</TabViewItem>
|
||||
|
||||
<TabViewItem title="Tab 3">
|
||||
<TabViewItem.view>
|
||||
<Label text="Label 3" />
|
||||
</TabViewItem.view>
|
||||
</TabViewItem>
|
||||
</TabView.items>
|
||||
</TabView>
|
||||
</Page>
|
||||
@@ -19,7 +19,6 @@
|
||||
"devDependencies": {
|
||||
"@types/chai": "~4.1.7",
|
||||
"@types/mocha": "~5.2.5",
|
||||
"@types/node": "~10.12.18",
|
||||
"babel-traverse": "6.26.0",
|
||||
"babel-types": "6.26.0",
|
||||
"babylon": "6.18.0",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as application from "tns-core-modules/application";
|
||||
import { StackLayout } from "tns-core-modules/ui/layouts/stack-layout";
|
||||
import { NavigatedData, Page } from "tns-core-modules/ui/page";
|
||||
import { View, EventData } from "tns-core-modules/ui/core/view";
|
||||
import { View, EventData, ShowModalOptions } from "tns-core-modules/ui/core/view";
|
||||
import { Frame } from "tns-core-modules/ui/frame";
|
||||
|
||||
export function onNavigatingTo(args: NavigatedData) {
|
||||
@@ -29,6 +29,20 @@ export function onModalNoPage(args: EventData) {
|
||||
false);
|
||||
}
|
||||
|
||||
export function onPopoverModal(args: EventData) {
|
||||
const view = args.object as View;
|
||||
let options: ShowModalOptions = {
|
||||
context: "context",
|
||||
closeCallback: () => console.log("home-page modal popover frame closed"),
|
||||
animated: false,
|
||||
ios: {
|
||||
presentationStyle: UIModalPresentationStyle.Popover
|
||||
}
|
||||
}
|
||||
|
||||
view.showModal("modal-no-page/modal-no-page", options);
|
||||
}
|
||||
|
||||
export function onModalFrame(args: EventData) {
|
||||
const view = args.object as View;
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
<Button text="Show Modal Without Page" tap="onModalNoPage" textAlignment="left" />
|
||||
<Button text="Show Modal Page With Frame" tap="onModalFrame" textAlignment="left" />
|
||||
<Button text="Show Modal Page" tap="onModalPage" textAlignment="left" />
|
||||
<Button text="Show 'popover' modal" tap="onPopoverModal" textAlignment="left" />
|
||||
<Button text="Show Modal Layout" tap="onModalLayout" textAlignment="left" />
|
||||
<Button text="Show Modal TabView" tap="onModalTabView" textAlignment="left" />
|
||||
<Button text="Android Back Btn Events" tap="onAndroidBackEvents" textAlignment="left" />
|
||||
|
||||
@@ -3,7 +3,7 @@ import { NavigatedData, Page } from "tns-core-modules/ui/page";
|
||||
import { View, EventData } from "tns-core-modules/ui/core/view";
|
||||
import { Frame, ShownModallyData } from "tns-core-modules/ui/frame";
|
||||
import { fromObject } from "tns-core-modules/data/observable";
|
||||
import { confirm } from "ui/dialogs";
|
||||
import { confirm } from "tns-core-modules/ui/dialogs";
|
||||
|
||||
export function onLoaded(args) {
|
||||
console.log("modal-no-page loaded");
|
||||
|
||||
@@ -3,7 +3,7 @@ import { NavigatedData, Page } from "tns-core-modules/ui/page";
|
||||
import { View, EventData } from "tns-core-modules/ui/core/view";
|
||||
import { Frame, ShownModallyData } from "tns-core-modules/ui/frame";
|
||||
import { fromObject } from "tns-core-modules/data/observable";
|
||||
import { confirm } from "ui/dialogs";
|
||||
import { confirm } from "tns-core-modules/ui/dialogs";
|
||||
|
||||
export function onShowingModally(args: ShownModallyData) {
|
||||
console.log("modal-page showingModally");
|
||||
|
||||
@@ -19,13 +19,13 @@
|
||||
"devDependencies": {
|
||||
"@types/chai": "~4.1.7",
|
||||
"@types/mocha": "~5.2.5",
|
||||
"@types/node": "^7.0.5",
|
||||
"mocha": "~5.2.0",
|
||||
"mochawesome": "~3.1.2",
|
||||
"nativescript-dev-appium": "next",
|
||||
"nativescript-dev-typescript": "next",
|
||||
"nativescript-dev-webpack": "next",
|
||||
"rimraf": "^2.6.2",
|
||||
"tns-platform-declarations": "next",
|
||||
"typescript": "^3.1.6"
|
||||
},
|
||||
"scripts": {
|
||||
|
||||
1
e2e/modal-navigation/references.d.ts
vendored
Normal file
1
e2e/modal-navigation/references.d.ts
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/// <reference path="./node_modules/tns-platform-declarations/ios.d.ts" />
|
||||
@@ -19,7 +19,6 @@
|
||||
"devDependencies": {
|
||||
"@types/chai": "~4.1.7",
|
||||
"@types/mocha": "~5.2.5",
|
||||
"@types/node": "^7.0.5",
|
||||
"mocha": "~5.2.0",
|
||||
"mochawesome": "~3.1.2",
|
||||
"nativescript-dev-appium": "next",
|
||||
|
||||
@@ -80,7 +80,7 @@
|
||||
"test-watch-ios": "npm run pretest && concurrently --kill-others \"npm run tsc-tiw\" \"tns livesync ios --path tests --watch\"",
|
||||
"prepublish": "echo \"Development reminder for setup\n - tns-core-modules: npm run setup\n - tns-core-modules-widgets: npm run setup-widgets\n\"",
|
||||
"typedoc": "typedoc --tsconfig tsconfig.typedoc.json --out bin/dist/apiref --includeDeclarations --name NativeScript --theme ./node_modules/nativescript-typedoc-theme --excludeExternals --externalPattern \"**/+(tns-core-modules|module).d.ts\"",
|
||||
"dev-typedoc": "npm run typedoc && cd bin/dist/apiref && http-server",
|
||||
"dev-typedoc": "npm run typedoc && cd bin/dist/apiref && npx http-server",
|
||||
"test-tsc-es2016": "npm run tsc -- -p tsconfig.public.es2016.json",
|
||||
"tslint": "tslint --config build/tslint.json 'tns-core-modules/**/*.ts' 'tests/**/*.ts' 'apps/**/*.ts' 'e2e/**/*.ts' -e '**/node_modules/**' -e '**/platforms/**'",
|
||||
"madge-ios": "tsc --skipLibCheck && tns prepare ios --path tests && madge --circular tests/platforms/ios/tests/app/tns_modules/tns-core-modules",
|
||||
|
||||
@@ -1,9 +1,19 @@
|
||||
import * as imageCacheModule from "tns-core-modules/ui/image-cache";
|
||||
import * as imageSource from "tns-core-modules/image-source";
|
||||
import * as types from "tns-core-modules/utils/types";
|
||||
import { device } from "tns-core-modules/platform";
|
||||
import lazy from "tns-core-modules/utils/lazy";
|
||||
|
||||
import * as TKUnit from "../../TKUnit";
|
||||
|
||||
const sdkVersion = lazy(() => parseInt(device.sdkVersion));
|
||||
|
||||
export const test_ImageCache_ValidUrl = function() {
|
||||
// see https://github.com/NativeScript/NativeScript/issues/6643
|
||||
if (sdkVersion() < 20) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cache = new imageCacheModule.Cache();
|
||||
cache.maxRequests = 5;
|
||||
|
||||
|
||||
@@ -162,10 +162,10 @@ export class LabelTest extends testModule.UITest<LabelModule.Label> {
|
||||
const span = new Span();
|
||||
span.text = "long label";
|
||||
span.fontWeight = "bold";
|
||||
|
||||
|
||||
const span2 = new Span();
|
||||
span2.text = "long label";
|
||||
|
||||
|
||||
const formattedString = new FormattedString();
|
||||
formattedString.spans.push(span);
|
||||
formattedString.spans.push(span2);
|
||||
@@ -176,7 +176,7 @@ export class LabelTest extends testModule.UITest<LabelModule.Label> {
|
||||
const span3 = new Span();
|
||||
span3.text = "short label";
|
||||
span3.fontWeight = "bold";
|
||||
|
||||
|
||||
const formattedString2 = new FormattedString();
|
||||
formattedString2.spans.push(span3);
|
||||
label.formattedText = formattedString2;
|
||||
@@ -210,7 +210,7 @@ export class LabelTest extends testModule.UITest<LabelModule.Label> {
|
||||
const span = new Span();
|
||||
span.text = "short label";
|
||||
span.fontWeight = "bold";
|
||||
|
||||
|
||||
const formattedString = new FormattedString();
|
||||
formattedString.spans.push(span);
|
||||
label.formattedText = formattedString;
|
||||
@@ -220,10 +220,10 @@ export class LabelTest extends testModule.UITest<LabelModule.Label> {
|
||||
const span2 = new Span();
|
||||
span2.text = "long label";
|
||||
span2.fontWeight = "bold";
|
||||
|
||||
|
||||
const span3 = new Span();
|
||||
span3.text = "long label";
|
||||
|
||||
|
||||
const formattedString2 = new FormattedString();
|
||||
formattedString2.spans.push(span2);
|
||||
formattedString2.spans.push(span3);
|
||||
@@ -733,6 +733,21 @@ export class LabelTest extends testModule.UITest<LabelModule.Label> {
|
||||
return host;
|
||||
});
|
||||
}
|
||||
|
||||
public test_FormattedText_ShouldNotCrash_WheRemovedFromSpan() {
|
||||
const label = this.testView;
|
||||
label.color = new colorModule.Color("red");
|
||||
this.waitUntilTestElementIsLoaded();
|
||||
|
||||
const span = new Span();
|
||||
span.text = "test";
|
||||
|
||||
const formattedString = new FormattedString();
|
||||
formattedString.spans.push(span);
|
||||
|
||||
label._addChildFromBuilder("FormattedString", formattedString);
|
||||
label._removeView(formattedString);
|
||||
};
|
||||
}
|
||||
|
||||
export function createTestCase(): LabelTest {
|
||||
|
||||
@@ -18,6 +18,47 @@ export function test_releaseNativeObject_canBeCalledWithNativeObject() {
|
||||
}
|
||||
};
|
||||
|
||||
export function test_executeOnMainThread_Works(done: Function) {
|
||||
utils.executeOnMainThread(() => {
|
||||
try {
|
||||
TKUnit.assertTrue(utils.isMainThread());
|
||||
done();
|
||||
} catch (e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function test_dispatchToMainThread_Works(done: Function) {
|
||||
utils.dispatchToMainThread(() => {
|
||||
try {
|
||||
TKUnit.assertTrue(utils.isMainThread());
|
||||
done();
|
||||
} catch (e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
export function test_mainThreadify_PassesArgs(done: Function) {
|
||||
const expectedN = 434;
|
||||
const expectedB = true;
|
||||
const expectedS = "string";
|
||||
const f = utils.mainThreadify(function (n: number, b: boolean, s: string) {
|
||||
try {
|
||||
TKUnit.assertTrue(utils.isMainThread());
|
||||
TKUnit.assertEqual(n, expectedN);
|
||||
TKUnit.assertEqual(b, expectedB);
|
||||
TKUnit.assertEqual(s, expectedS);
|
||||
done();
|
||||
} catch (e) {
|
||||
done(e);
|
||||
}
|
||||
});
|
||||
|
||||
f(expectedN, expectedB, expectedS);
|
||||
}
|
||||
|
||||
function test_releaseNativeObject_canBeCalledWithNativeObject_iOS() {
|
||||
let deallocated = false;
|
||||
const obj = new ((<any>NSObject).extend({
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tns-core-modules-widgets",
|
||||
"version": "5.4.0",
|
||||
"version": "6.0.0",
|
||||
"description": "Native widgets used in the NativeScript framework.",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
notify, launchEvent, resumeEvent, suspendEvent, exitEvent, lowMemoryEvent,
|
||||
orientationChangedEvent, setApplication, livesync, displayedEvent, getCssFileName
|
||||
} from "./application-common";
|
||||
import { ModuleType } from "../ui/core/view/view-common";
|
||||
|
||||
// First reexport so that app module is initialized.
|
||||
export * from "./application-common";
|
||||
@@ -231,7 +230,7 @@ class IOSApplication implements IOSApplicationDefinition {
|
||||
|
||||
public _onLivesync(context?: ModuleContext): void {
|
||||
// Handle application root module
|
||||
const isAppRootModuleChanged = context && context.path && context.path.includes(getMainEntry().moduleName) && context.type !== ModuleType.style;
|
||||
const isAppRootModuleChanged = context && context.path && context.path.includes(getMainEntry().moduleName) && context.type !== "style";
|
||||
|
||||
// Set window content when:
|
||||
// + Application root module is changed
|
||||
|
||||
@@ -2,6 +2,7 @@ import { getNodeById } from "./dom-node";
|
||||
|
||||
// Needed for typings only
|
||||
import { ViewBase } from "../ui/core/view-base";
|
||||
import { mainThreadify } from "../utils/utils";
|
||||
|
||||
// Use lazy requires for core modules
|
||||
const frameTopmost = () => require("../ui/frame").topmost();
|
||||
@@ -11,7 +12,7 @@ function unsetViewValue(view, name) {
|
||||
if (!unsetValue) {
|
||||
unsetValue = require("../ui/core/properties").unsetValue;
|
||||
}
|
||||
|
||||
|
||||
view[name] = unsetValue;
|
||||
}
|
||||
|
||||
@@ -30,10 +31,10 @@ export function getDocument() {
|
||||
if (!topMostFrame) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
topMostFrame.ensureDomNode();
|
||||
|
||||
|
||||
} catch (e) {
|
||||
console.log("ERROR in getDocument(): " + e);
|
||||
}
|
||||
@@ -49,7 +50,7 @@ export function getComputedStylesForNode(nodeId): Array<{ name: string, value: s
|
||||
return [];
|
||||
}
|
||||
|
||||
export function removeNode(nodeId) {
|
||||
export const removeNode = mainThreadify(function removeNode(nodeId) {
|
||||
const view = getViewById(nodeId);
|
||||
if (view) {
|
||||
// Avoid importing layout and content view
|
||||
@@ -63,9 +64,9 @@ export function removeNode(nodeId) {
|
||||
console.log("Can't remove child from " + parent);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export function setAttributeAsText(nodeId, text, name) {
|
||||
export const setAttributeAsText = mainThreadify(function setAttributeAsText(nodeId, text, name) {
|
||||
const view = getViewById(nodeId);
|
||||
if (view) {
|
||||
// attribute is registered for the view instance
|
||||
@@ -93,4 +94,4 @@ export function setAttributeAsText(nodeId, text, name) {
|
||||
|
||||
view.domNode.loadAttributes();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
6
tns-core-modules/module.d.ts
vendored
6
tns-core-modules/module.d.ts
vendored
@@ -66,11 +66,7 @@ declare function clearTimeout(timeoutId: number): void;
|
||||
declare function setInterval(callback: (...args: any[]) => void, ms: number, ...args: any[]): number;
|
||||
declare function clearInterval(intervalId: number): void;
|
||||
|
||||
declare enum ModuleType {
|
||||
markup = "markup",
|
||||
script = "script",
|
||||
style = "style"
|
||||
}
|
||||
declare type ModuleType = "markup" | "script" | "style";
|
||||
|
||||
/**
|
||||
* Define a module context for Hot Module Replacement.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "tns-core-modules",
|
||||
"description": "Telerik NativeScript Core Modules",
|
||||
"version": "5.4.0",
|
||||
"version": "6.0.0",
|
||||
"homepage": "https://www.nativescript.org",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
@@ -5,9 +5,13 @@
|
||||
} from "./button-common";
|
||||
import { profile } from "../../profiling";
|
||||
import { TouchGestureEventData, GestureTypes, TouchAction } from "../gestures";
|
||||
import { device } from "../../platform";
|
||||
import lazy from "../../utils/lazy";
|
||||
|
||||
export * from "./button-common";
|
||||
|
||||
const sdkVersion = lazy(() => parseInt(device.sdkVersion));
|
||||
|
||||
interface ClickListener {
|
||||
new(owner: Button): android.view.View.OnClickListener;
|
||||
}
|
||||
@@ -151,4 +155,23 @@ export class Button extends ButtonBase {
|
||||
const newValue = value === "initial" ? "center" : value;
|
||||
super[textAlignmentProperty.setNative](newValue);
|
||||
}
|
||||
}
|
||||
|
||||
protected getDefaultElevation(): number {
|
||||
if (sdkVersion() < 21) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: Button widget has StateListAnimator that defines the elevation value and
|
||||
// at the time of the getDefault() query the animator is not applied yet so we
|
||||
// return the hardcoded @dimen/button_elevation_material value 2dp here instead
|
||||
return 2;
|
||||
}
|
||||
|
||||
protected getDefaultDynamicElevationOffset(): number {
|
||||
if (sdkVersion() < 21) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 4; // 4dp @dimen/button_pressed_z_material
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1018,7 +1018,7 @@ export const classNameProperty = new Property<ViewBase, string>({
|
||||
valueChanged(view: ViewBase, oldValue: string, newValue: string) {
|
||||
let classes = view.cssClasses;
|
||||
classes.clear();
|
||||
if (typeof newValue === "string") {
|
||||
if (typeof newValue === "string" && newValue !== "") {
|
||||
newValue.split(" ").forEach(c => classes.add(c));
|
||||
}
|
||||
view._onCssStateChange();
|
||||
|
||||
@@ -21,6 +21,7 @@ import {
|
||||
} from "../../gestures";
|
||||
|
||||
import { createViewFromEntry } from "../../builder";
|
||||
import { isAndroid } from "../../../platform";
|
||||
import { StyleScope } from "../../styling/style-scope";
|
||||
import { LinearGradient } from "../../styling/linear-gradient";
|
||||
import { BackgroundRepeat } from "../../styling/style-properties";
|
||||
@@ -37,18 +38,25 @@ function ensureAnimationModule() {
|
||||
}
|
||||
}
|
||||
|
||||
export enum ModuleType {
|
||||
markup = "markup",
|
||||
script = "script",
|
||||
style = "style"
|
||||
}
|
||||
|
||||
export function CSSType(type: string): ClassDecorator {
|
||||
return (cls) => {
|
||||
cls.prototype.cssType = type;
|
||||
};
|
||||
}
|
||||
|
||||
export function viewMatchesModuleContext(
|
||||
view: ViewDefinition,
|
||||
context: ModuleContext,
|
||||
types: ModuleType[]): boolean {
|
||||
|
||||
return context &&
|
||||
view._moduleName &&
|
||||
context.type &&
|
||||
types.some(type => type === context.type) &&
|
||||
context.path &&
|
||||
context.path.includes(view._moduleName);
|
||||
}
|
||||
|
||||
export function PseudoClassHandler(...pseudoClasses: string[]): MethodDecorator {
|
||||
const stateEventNames = pseudoClasses.map(s => ":" + s);
|
||||
const listeners = Symbol("listeners");
|
||||
@@ -147,62 +155,36 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
|
||||
traceWrite(`${this}._onLivesync(${JSON.stringify(context)})`, traceCategories.Livesync);
|
||||
}
|
||||
|
||||
_rootModalViews.forEach(v => v.closeModal());
|
||||
_rootModalViews.length = 0;
|
||||
|
||||
if (context && context.type && context.path) {
|
||||
// Handle local styles
|
||||
if (context.type === ModuleType.style) {
|
||||
return this.changeLocalStyles(context.path);
|
||||
}
|
||||
// Handle module markup and script changes
|
||||
else {
|
||||
return this.changeModule(context);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private changeLocalStyles(contextPath: string): boolean {
|
||||
if (!this.changeStyles(this, contextPath)) {
|
||||
eachDescendant(this, (child: ViewBase) => {
|
||||
this.changeStyles(child, contextPath);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
// Do not reset activity/window content for local styles changes
|
||||
return true;
|
||||
}
|
||||
|
||||
private changeStyles(view: ViewBase, contextPath: string): boolean {
|
||||
if (traceEnabled()) {
|
||||
traceWrite(`${view}.${view._moduleName}`, traceCategories.Livesync);
|
||||
}
|
||||
|
||||
if (view._moduleName && contextPath.includes(view._moduleName)) {
|
||||
(<this>view).changeCssFile(contextPath);
|
||||
if (this._handleLivesync(context)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private changeModule(context: ModuleContext): boolean {
|
||||
eachDescendant(this, (child: ViewBase) => {
|
||||
if (traceEnabled()) {
|
||||
traceWrite(`${child}.${child._moduleName}`, traceCategories.Livesync);
|
||||
let handled = false;
|
||||
this.eachChildView((child) => {
|
||||
if (child._onLivesync(context)) {
|
||||
handled = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Handle changes in module's Page
|
||||
if (child._moduleName && context.path.includes(child._moduleName) && child.page) {
|
||||
child.page._onLivesync(context);
|
||||
}
|
||||
return true;
|
||||
});
|
||||
return handled;
|
||||
}
|
||||
|
||||
// Do not reset activity/window content for module changes
|
||||
return true;
|
||||
public _handleLivesync(context?: ModuleContext): boolean {
|
||||
if (traceEnabled()) {
|
||||
traceWrite(`${this}._handleLivesync(${JSON.stringify(context)})`, traceCategories.Livesync);
|
||||
}
|
||||
|
||||
// Handle local CSS
|
||||
if (viewMatchesModuleContext(this, context, ["style"])) {
|
||||
if (traceEnabled()) {
|
||||
traceWrite(`Change Handled: Changing CSS for ${this}`, traceCategories.Livesync);
|
||||
}
|
||||
|
||||
this.changeCssFile(context.path);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
_setupAsRootView(context: any): void {
|
||||
@@ -368,7 +350,11 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
|
||||
}
|
||||
}
|
||||
|
||||
that._hideNativeModalView(parent, whenClosedCallback);
|
||||
if (isAndroid || (parent.viewController && parent.viewController.presentedViewController)) {
|
||||
that._hideNativeModalView(parent, whenClosedCallback);
|
||||
} else {
|
||||
whenClosedCallback();
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -697,6 +683,20 @@ export abstract class ViewCommon extends ViewBase implements ViewDefinition {
|
||||
this.style.scaleY = value;
|
||||
}
|
||||
|
||||
get androidElevation(): number {
|
||||
return this.style.androidElevation;
|
||||
}
|
||||
set androidElevation(value: number) {
|
||||
this.style.androidElevation = value;
|
||||
}
|
||||
|
||||
get androidDynamicElevationOffset(): number {
|
||||
return this.style.androidDynamicElevationOffset;
|
||||
}
|
||||
set androidDynamicElevationOffset(value: number) {
|
||||
this.style.androidDynamicElevationOffset = value;
|
||||
}
|
||||
|
||||
//END Style property shortcuts
|
||||
|
||||
public automationText: string;
|
||||
|
||||
@@ -15,19 +15,27 @@ import {
|
||||
minWidthProperty, minHeightProperty, widthProperty, heightProperty,
|
||||
marginLeftProperty, marginTopProperty, marginRightProperty, marginBottomProperty,
|
||||
rotateProperty, scaleXProperty, scaleYProperty, translateXProperty, translateYProperty,
|
||||
zIndexProperty, backgroundInternalProperty
|
||||
zIndexProperty, backgroundInternalProperty, androidElevationProperty, androidDynamicElevationOffsetProperty
|
||||
} from "../../styling/style-properties";
|
||||
|
||||
import { Background, ad as androidBackground } from "../../styling/background";
|
||||
import { profile } from "../../../profiling";
|
||||
import { topmost } from "../../frame/frame-stack";
|
||||
import { AndroidActivityBackPressedEventData, android as androidApp } from "../../../application";
|
||||
import { device } from "../../../platform";
|
||||
import lazy from "../../../utils/lazy";
|
||||
|
||||
export * from "./view-common";
|
||||
|
||||
const DOMID = "_domId";
|
||||
const androidBackPressedEvent = "androidBackPressed";
|
||||
|
||||
const shortAnimTime = 17694720; // android.R.integer.config_shortAnimTime
|
||||
const statePressed = 16842919; // android.R.attr.state_pressed
|
||||
const stateEnabled = 16842910; // android.R.attr.state_enabled
|
||||
|
||||
const sdkVersion = lazy(() => parseInt(device.sdkVersion));
|
||||
|
||||
const modalMap = new Map<number, DialogOptions>();
|
||||
|
||||
let TouchListener: TouchListener;
|
||||
@@ -255,6 +263,8 @@ export class View extends ViewCommon {
|
||||
private layoutChangeListener: android.view.View.OnLayoutChangeListener;
|
||||
private _manager: android.support.v4.app.FragmentManager;
|
||||
private _rootManager: android.support.v4.app.FragmentManager;
|
||||
private _originalElevation: number;
|
||||
private _originalStateListAnimator: any; /* android.animation.StateListAnimator; */
|
||||
|
||||
nativeViewProtected: android.view.View;
|
||||
|
||||
@@ -709,6 +719,94 @@ export class View extends ViewCommon {
|
||||
this.nativeViewProtected.setAlpha(float(value));
|
||||
}
|
||||
|
||||
[androidElevationProperty.getDefault](): number {
|
||||
return this.getDefaultElevation();
|
||||
}
|
||||
[androidElevationProperty.setNative](value: number) {
|
||||
if (sdkVersion() < 21) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.refreshStateListAnimator();
|
||||
}
|
||||
|
||||
[androidDynamicElevationOffsetProperty.getDefault](): number {
|
||||
return this.getDefaultDynamicElevationOffset();
|
||||
}
|
||||
[androidDynamicElevationOffsetProperty.setNative](value: number) {
|
||||
if (sdkVersion() < 21) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.refreshStateListAnimator();
|
||||
}
|
||||
|
||||
protected getDefaultElevation(): number {
|
||||
if (sdkVersion() < 21) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// NOTE: overriden in Button implementation as for widgets with StateListAnimator (Button)
|
||||
// nativeView.getElevation() returns 0 at the time of the getDefault() query
|
||||
return layout.toDeviceIndependentPixels((<any>this.nativeViewProtected).getElevation());
|
||||
}
|
||||
|
||||
protected getDefaultDynamicElevationOffset() {
|
||||
// NOTE: overriden in Button implementation
|
||||
return 0;
|
||||
}
|
||||
|
||||
private refreshStateListAnimator() {
|
||||
const nativeView: any = this.nativeViewProtected;
|
||||
|
||||
const ObjectAnimator = android.animation.ObjectAnimator;
|
||||
const AnimatorSet = android.animation.AnimatorSet;
|
||||
|
||||
const duration = nativeView.getContext().getResources().getInteger(shortAnimTime) / 2;
|
||||
|
||||
let elevation = this.androidElevation;
|
||||
if (typeof elevation === "undefined" || elevation === null) {
|
||||
elevation = this.getDefaultElevation();
|
||||
}
|
||||
elevation = layout.toDevicePixels(elevation);
|
||||
|
||||
const z = layout.toDevicePixels(0);
|
||||
|
||||
let pressedZ = this.androidDynamicElevationOffset;
|
||||
if (typeof pressedZ === "undefined" || pressedZ === null) {
|
||||
pressedZ = this.getDefaultDynamicElevationOffset();
|
||||
}
|
||||
pressedZ = layout.toDevicePixels(pressedZ);
|
||||
|
||||
const pressedSet = new AnimatorSet();
|
||||
pressedSet.playTogether(java.util.Arrays.asList([
|
||||
ObjectAnimator.ofFloat(nativeView, "translationZ", [pressedZ])
|
||||
.setDuration(duration),
|
||||
ObjectAnimator.ofFloat(nativeView, "elevation", [elevation])
|
||||
.setDuration(0),
|
||||
]));
|
||||
|
||||
const notPressedSet = new AnimatorSet();
|
||||
notPressedSet.playTogether(java.util.Arrays.asList([
|
||||
ObjectAnimator.ofFloat(nativeView, "translationZ", [z])
|
||||
.setDuration(duration),
|
||||
ObjectAnimator.ofFloat(nativeView, "elevation", [elevation])
|
||||
.setDuration(0),
|
||||
]));
|
||||
|
||||
const defaultSet = new AnimatorSet();
|
||||
defaultSet.playTogether(java.util.Arrays.asList([
|
||||
ObjectAnimator.ofFloat(nativeView, "translationZ", [0]).setDuration(0),
|
||||
ObjectAnimator.ofFloat(nativeView, "elevation", [0]).setDuration(0),
|
||||
]));
|
||||
|
||||
const stateListAnimator = new (<any>android.animation).StateListAnimator();
|
||||
stateListAnimator.addState([statePressed, stateEnabled], pressedSet);
|
||||
stateListAnimator.addState([stateEnabled], notPressedSet);
|
||||
stateListAnimator.addState([], defaultSet);
|
||||
nativeView.setStateListAnimator(stateListAnimator);
|
||||
}
|
||||
|
||||
[horizontalAlignmentProperty.getDefault](): HorizontalAlignment {
|
||||
return <HorizontalAlignment>org.nativescript.widgets.ViewHelper.getHorizontalAlignment(this.nativeViewProtected);
|
||||
}
|
||||
@@ -946,7 +1044,7 @@ function createNativePercentLengthProperty(options: NativePercentLengthPropertyO
|
||||
const { getter, setter, auto = 0 } = options;
|
||||
let setPixels, getPixels, setPercent;
|
||||
if (getter) {
|
||||
View.prototype[getter] = function (this: View): PercentLength {
|
||||
View.prototype[getter] = function(this: View): PercentLength {
|
||||
if (options) {
|
||||
setPixels = options.setPixels;
|
||||
getPixels = options.getPixels;
|
||||
@@ -962,7 +1060,7 @@ function createNativePercentLengthProperty(options: NativePercentLengthPropertyO
|
||||
}
|
||||
}
|
||||
if (setter) {
|
||||
View.prototype[setter] = function (this: View, length: PercentLength) {
|
||||
View.prototype[setter] = function(this: View, length: PercentLength) {
|
||||
if (options) {
|
||||
setPixels = options.setPixels;
|
||||
getPixels = options.getPixels;
|
||||
|
||||
27
tns-core-modules/ui/core/view/view.d.ts
vendored
27
tns-core-modules/ui/core/view/view.d.ts
vendored
@@ -32,6 +32,17 @@ export function PseudoClassHandler(...pseudoClasses: string[]): MethodDecorator;
|
||||
*/
|
||||
export function CSSType(type: string): ClassDecorator;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param view The view
|
||||
* @param context The ModuleType
|
||||
* @param type Type of the ModuleType to be matched
|
||||
*/
|
||||
export function viewMatchesModuleContext(
|
||||
view: View,
|
||||
context: ModuleContext,
|
||||
type: ModuleType[]): boolean;
|
||||
|
||||
/**
|
||||
* Denotes a length number that is in device independent pixel units.
|
||||
*/
|
||||
@@ -213,6 +224,16 @@ export abstract class View extends ViewBase {
|
||||
*/
|
||||
color: Color;
|
||||
|
||||
/**
|
||||
* Gets or sets the elevation of the android view.
|
||||
*/
|
||||
androidElevation: number;
|
||||
|
||||
/**
|
||||
* Gets or sets the dynamic elevation offset of the android view.
|
||||
*/
|
||||
androidDynamicElevationOffset: number;
|
||||
|
||||
/**
|
||||
* Gets or sets the background style property.
|
||||
*/
|
||||
@@ -474,7 +495,7 @@ export abstract class View extends ViewBase {
|
||||
|
||||
/**
|
||||
* @deprecated use on() instead
|
||||
*
|
||||
*
|
||||
* @param type - Type of the gesture.
|
||||
* @param callback - A function that will be executed when gesture is received.
|
||||
* @param thisArg - An optional parameter which will be used as `this` context for callback execution.
|
||||
@@ -683,6 +704,10 @@ export abstract class View extends ViewBase {
|
||||
* @private
|
||||
*/
|
||||
_onLivesync(context?: { type: string, path: string }): boolean;
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
_handleLivesync(context?: { type: string, path: string }): boolean;
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
|
||||
@@ -29,6 +29,7 @@ const majorVersion = iosUtils.MajorVersion;
|
||||
export class View extends ViewCommon {
|
||||
nativeViewProtected: UIView;
|
||||
viewController: UIViewController;
|
||||
private _popoverPresentationDelegate: ios.UIPopoverPresentationControllerDelegateImp;
|
||||
|
||||
private _isLaidOut = false;
|
||||
private _hasTransfrom = false;
|
||||
@@ -416,6 +417,8 @@ export class View extends ViewCommon {
|
||||
|
||||
if (presentationStyle === UIModalPresentationStyle.Popover) {
|
||||
const popoverPresentationController = controller.popoverPresentationController;
|
||||
this._popoverPresentationDelegate = ios.UIPopoverPresentationControllerDelegateImp.initWithOwnerAndCallback(new WeakRef(this), this._closeModalCallback);
|
||||
popoverPresentationController.delegate = this._popoverPresentationDelegate;
|
||||
const view = parent.nativeViewProtected;
|
||||
// Note: sourceView and sourceRect are needed to specify the anchor location for the popover.
|
||||
// Note: sourceView should be the button triggering the modal. If it the Page the popover might appear "behind" the page content
|
||||
@@ -906,7 +909,7 @@ export namespace ios {
|
||||
|
||||
public viewDidLoad(): void {
|
||||
super.viewDidLoad();
|
||||
|
||||
|
||||
// Unify translucent and opaque bars layout
|
||||
// this.edgesForExtendedLayout = UIRectEdgeBottom;
|
||||
this.extendedLayoutIncludesOpaqueBars = true;
|
||||
@@ -982,4 +985,26 @@ export namespace ios {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class UIPopoverPresentationControllerDelegateImp extends NSObject implements UIPopoverPresentationControllerDelegate {
|
||||
public static ObjCProtocols = [UIPopoverPresentationControllerDelegate];
|
||||
|
||||
private owner: WeakRef<View>;
|
||||
private closedCallback: Function;
|
||||
|
||||
public static initWithOwnerAndCallback(owner: WeakRef<View>, whenClosedCallback: Function): UIPopoverPresentationControllerDelegateImp {
|
||||
const instance = <UIPopoverPresentationControllerDelegateImp>super.new();
|
||||
instance.owner = owner;
|
||||
instance.closedCallback = whenClosedCallback;
|
||||
|
||||
return instance;
|
||||
}
|
||||
|
||||
public popoverPresentationControllerDidDismissPopover(popoverPresentationController: UIPopoverPresentationController) {
|
||||
const owner = this.owner.get();
|
||||
if (owner && typeof this.closedCallback === "function") {
|
||||
this.closedCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,12 +3,13 @@ import { Frame as FrameDefinition, NavigationEntry, BackstackEntry, NavigationTr
|
||||
import { Page } from "../page";
|
||||
|
||||
// Types.
|
||||
import { getAncestor } from "../core/view/view-common";
|
||||
import { getAncestor, viewMatchesModuleContext } from "../core/view/view-common";
|
||||
import { View, CustomLayoutView, isIOS, isAndroid, traceEnabled, traceWrite, traceCategories, Property, CSSType } from "../core/view";
|
||||
import { createViewFromEntry } from "../builder";
|
||||
import { profile } from "../../profiling";
|
||||
|
||||
import { frameStack, topmost as frameStackTopmost, _pushInFrameStack, _popFromFrameStack, _removeFromFrameStack } from "./frame-stack";
|
||||
import { getModuleName } from "../../utils/utils";
|
||||
export * from "../core/view";
|
||||
|
||||
export enum NavigationType {
|
||||
@@ -574,7 +575,38 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
|
||||
return result;
|
||||
}
|
||||
|
||||
public _onLivesync(): boolean {
|
||||
public _onLivesync(context?: ModuleContext): boolean {
|
||||
if (super._onLivesync(context)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Fallback
|
||||
if (!context) {
|
||||
return this.legacyLivesync();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public _handleLivesync(context?: ModuleContext): boolean {
|
||||
if (super._handleLivesync(context)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Handle markup/script changes in currentPage
|
||||
if (this.currentPage &&
|
||||
viewMatchesModuleContext(this.currentPage, context, ["markup", "script"])) {
|
||||
|
||||
traceWrite(`Change Handled: Replacing page ${context.path}`, traceCategories.Livesync);
|
||||
|
||||
this.replacePage(context);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private legacyLivesync(): boolean {
|
||||
// Reset activity/window content when:
|
||||
// + Changes are not handled on View
|
||||
// + There is no ModuleContext
|
||||
@@ -609,6 +641,27 @@ export class FrameBase extends CustomLayoutView implements FrameDefinition {
|
||||
this.navigate(newEntry);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected replacePage(context: ModuleContext): void {
|
||||
// Set NavigationType.replace for HMR.
|
||||
// In IOS on `viewDidAppear()` this will be set to NavigationType.forward.
|
||||
this.navigationType = NavigationType.replace;
|
||||
const currentBackstackEntry = this._currentEntry;
|
||||
const contextModuleName = getModuleName(context.path);
|
||||
|
||||
const newPage = <Page>createViewFromEntry({ moduleName: contextModuleName });
|
||||
const newBackstackEntry: BackstackEntry = {
|
||||
entry: currentBackstackEntry.entry,
|
||||
resolvedPage: newPage,
|
||||
navDepth: currentBackstackEntry.navDepth,
|
||||
fragmentTag: currentBackstackEntry.fragmentTag,
|
||||
frameId: currentBackstackEntry.frameId
|
||||
};
|
||||
|
||||
const navContext: NavigationContext = { entry: newBackstackEntry, isBackNavigation: false };
|
||||
this.performNavigation(navContext);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export function getFrameById(id: string): FrameBase {
|
||||
|
||||
@@ -3,7 +3,6 @@ import {
|
||||
AndroidFrame as AndroidFrameDefinition, AndroidActivityCallbacks,
|
||||
AndroidFragmentCallbacks, BackstackEntry, NavigationTransition
|
||||
} from ".";
|
||||
import { ModuleType } from "../../ui/core/view/view-common";
|
||||
import { Page } from "../page";
|
||||
|
||||
// Types.
|
||||
@@ -90,7 +89,7 @@ export function reloadPage(context?: ModuleContext): void {
|
||||
if (callbacks) {
|
||||
const rootView: View = callbacks.getRootView();
|
||||
// Handle application root module
|
||||
const isAppRootModuleChanged = context && context.path && context.path.includes(application.getMainEntry().moduleName) && context.type !== ModuleType.style;
|
||||
const isAppRootModuleChanged = context && context.path && context.path.includes(application.getMainEntry().moduleName) && context.type !== "style";
|
||||
|
||||
// Reset activity content when:
|
||||
// + Application root module is changed
|
||||
@@ -339,39 +338,6 @@ export class Frame extends FrameBase {
|
||||
return false;
|
||||
}
|
||||
|
||||
public _onLivesync(context?: ModuleContext): boolean {
|
||||
if (traceEnabled()) {
|
||||
traceWrite(`${this}._onLivesync(${JSON.stringify(context)})`, traceCategories.Livesync);
|
||||
}
|
||||
|
||||
if (!this._currentEntry || !this._currentEntry.entry) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context && context.type && context.path) {
|
||||
// Set NavigationType.replace for HMR.
|
||||
this.navigationType = NavigationType.replace;
|
||||
const currentBackstackEntry = this._currentEntry;
|
||||
const contextModuleName = getModuleName(context.path);
|
||||
|
||||
const newPage = <Page>createViewFromEntry({ moduleName: contextModuleName });
|
||||
const newBackstackEntry: BackstackEntry = {
|
||||
entry: currentBackstackEntry.entry,
|
||||
resolvedPage: newPage,
|
||||
navDepth: currentBackstackEntry.navDepth,
|
||||
fragmentTag: currentBackstackEntry.fragmentTag,
|
||||
frameId: currentBackstackEntry.frameId
|
||||
};
|
||||
|
||||
const navContext: NavigationContext = { entry: newBackstackEntry, isBackNavigation: false };
|
||||
this.performNavigation(navContext);
|
||||
return true;
|
||||
} else {
|
||||
// Fallback
|
||||
return super._onLivesync();
|
||||
}
|
||||
}
|
||||
|
||||
@profile
|
||||
public _navigateCore(newEntry: BackstackEntry) {
|
||||
super._navigateCore(newEntry);
|
||||
|
||||
@@ -63,39 +63,6 @@ export class Frame extends FrameBase {
|
||||
}
|
||||
}
|
||||
|
||||
public _onLivesync(context?: ModuleContext): boolean {
|
||||
if (traceEnabled()) {
|
||||
traceWrite(`${this}._onLivesync(${JSON.stringify(context)})`, traceCategories.Livesync);
|
||||
}
|
||||
|
||||
if (!this._currentEntry || !this._currentEntry.entry) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (context && context.type && context.path) {
|
||||
// Set NavigationType.replace for HMR.
|
||||
// When `viewDidAppear()` set to NavigationType.forward.
|
||||
this.navigationType = NavigationType.replace;
|
||||
const currentBackstackEntry = this._currentEntry;
|
||||
|
||||
const contextModuleName = utils.getModuleName(context.path);
|
||||
const newPage = <Page>createViewFromEntry({ moduleName: contextModuleName });
|
||||
const newBackstackEntry: BackstackEntry = {
|
||||
entry: currentBackstackEntry.entry,
|
||||
resolvedPage: newPage,
|
||||
navDepth: currentBackstackEntry.navDepth,
|
||||
fragmentTag: undefined
|
||||
}
|
||||
|
||||
const navContext: NavigationContext = { entry: newBackstackEntry, isBackNavigation: false };
|
||||
this.performNavigation(navContext);
|
||||
return true;
|
||||
} else {
|
||||
// Fallback
|
||||
return super._onLivesync();
|
||||
}
|
||||
}
|
||||
|
||||
@profile
|
||||
public _navigateCore(backstackEntry: BackstackEntry) {
|
||||
// NavigationType.replace for HMR.
|
||||
|
||||
@@ -99,10 +99,6 @@ export class PageBase extends ContentView implements PageDefinition {
|
||||
};
|
||||
}
|
||||
|
||||
public _onLivesync(context?: ModuleContext): boolean {
|
||||
return this.frame ? this.frame._onLivesync(context) : false;
|
||||
}
|
||||
|
||||
@profile
|
||||
public onNavigatingTo(context: any, isBackNavigation: boolean, bindingContext?: any) {
|
||||
this._navigationContext = context;
|
||||
|
||||
@@ -1127,3 +1127,9 @@ export const visibilityProperty = new CssProperty<Style, Visibility>({
|
||||
}
|
||||
});
|
||||
visibilityProperty.register(Style);
|
||||
|
||||
export const androidElevationProperty = new CssProperty<Style, number>({ name: "androidElevation", cssName: "android-elevation", valueConverter: parseFloat });
|
||||
androidElevationProperty.register(Style);
|
||||
|
||||
export const androidDynamicElevationOffsetProperty = new CssProperty<Style, number>({ name: "androidDynamicElevationOffset", cssName: "android-dynamic-elevation-offset", valueConverter: parseFloat });
|
||||
androidDynamicElevationOffsetProperty.register(Style);
|
||||
|
||||
8
tns-core-modules/ui/styling/style/style.d.ts
vendored
8
tns-core-modules/ui/styling/style/style.d.ts
vendored
@@ -92,6 +92,8 @@ export class Style extends Observable {
|
||||
public fontWeight: FontWeight;
|
||||
public font: string;
|
||||
|
||||
public androidElevation: number;
|
||||
public androidDynamicElevationOffset: number;
|
||||
public zIndex: number;
|
||||
public opacity: number;
|
||||
public visibility: Visibility;
|
||||
@@ -127,13 +129,13 @@ export class Style extends Observable {
|
||||
public selectedTabTextColor: Color;
|
||||
public androidSelectedTabHighlightColor: Color;
|
||||
|
||||
// ListView-specific props
|
||||
// ListView-specific props
|
||||
public separatorColor: Color;
|
||||
|
||||
//SegmentedBar-specific props
|
||||
public selectedBackgroundColor: Color;
|
||||
|
||||
// Page-specific props
|
||||
// Page-specific props
|
||||
public statusBarStyle: "light" | "dark";
|
||||
public androidStatusBarBackground: Color;
|
||||
|
||||
@@ -167,4 +169,4 @@ interface PropertyBagClass {
|
||||
}
|
||||
interface PropertyBag {
|
||||
[property: string]: string;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,6 +65,8 @@ export class Style extends Observable implements StyleDefinition {
|
||||
public fontWeight: FontWeight;
|
||||
public font: string;
|
||||
|
||||
public androidElevation: number;
|
||||
public androidDynamicElevationOffset: number;
|
||||
public zIndex: number;
|
||||
public opacity: number;
|
||||
public visibility: Visibility;
|
||||
@@ -100,13 +102,13 @@ export class Style extends Observable implements StyleDefinition {
|
||||
public selectedTabTextColor: Color;
|
||||
public androidSelectedTabHighlightColor: Color;
|
||||
|
||||
// ListView-specific props
|
||||
// ListView-specific props
|
||||
public separatorColor: Color;
|
||||
|
||||
//SegmentedBar-specific props
|
||||
public selectedBackgroundColor: Color;
|
||||
|
||||
// Page-specific props
|
||||
// Page-specific props
|
||||
public statusBarStyle: "light" | "dark";
|
||||
public androidStatusBarBackground: Color;
|
||||
|
||||
@@ -124,4 +126,4 @@ export class Style extends Observable implements StyleDefinition {
|
||||
|
||||
public PropertyBag: { new(): { [property: string]: string }, prototype: { [property: string]: string } };
|
||||
}
|
||||
Style.prototype.PropertyBag = class { [property: string]: string; }
|
||||
Style.prototype.PropertyBag = class { [property: string]: string; }
|
||||
|
||||
@@ -576,7 +576,7 @@ function getTitleAttributesForStates(tabView: TabView): TabStates {
|
||||
}
|
||||
|
||||
const tabSelectedItemTextColor = tabView.style.selectedTabTextColor;
|
||||
const selectedTextColor = tabItemTextColor instanceof Color ? tabSelectedItemTextColor.ios : null;
|
||||
const selectedTextColor = tabSelectedItemTextColor instanceof Color ? tabSelectedItemTextColor.ios : null;
|
||||
result.selectedState = { [NSFontAttributeName]: font }
|
||||
if (selectedTextColor) {
|
||||
result.selectedState[UITextAttributeTextColor] = selectedTextColor
|
||||
|
||||
@@ -12,7 +12,7 @@ import { isString } from "../../utils/types";
|
||||
export * from "./text-base-common";
|
||||
|
||||
interface TextTransformation {
|
||||
new (owner: TextBase): android.text.method.TransformationMethod;
|
||||
new(owner: TextBase): android.text.method.TransformationMethod;
|
||||
}
|
||||
|
||||
let TextTransformation: TextTransformation;
|
||||
@@ -344,7 +344,7 @@ export function getTransformedText(text: string, textTransform: TextTransform):
|
||||
}
|
||||
|
||||
function createSpannableStringBuilder(formattedString: FormattedString): android.text.SpannableStringBuilder {
|
||||
if (!formattedString) {
|
||||
if (!formattedString || !formattedString.parent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -231,7 +231,7 @@ export class TextBase extends TextBaseCommon {
|
||||
|
||||
createNSMutableAttributedString(formattedString: FormattedString): NSMutableAttributedString {
|
||||
let mas = NSMutableAttributedString.alloc().init();
|
||||
if (formattedString) {
|
||||
if (formattedString && formattedString.parent) {
|
||||
for (let i = 0, spanStart = 0, length = formattedString.spans.length; i < length; i++) {
|
||||
const span = formattedString.spans.getItem(i);
|
||||
const text = span.text;
|
||||
|
||||
10
tns-core-modules/utils/mainthread-helper.android.ts
Normal file
10
tns-core-modules/utils/mainthread-helper.android.ts
Normal file
@@ -0,0 +1,10 @@
|
||||
export function dispatchToMainThread(func: () => void) {
|
||||
new android.os.Handler(android.os.Looper.getMainLooper())
|
||||
.post(new java.lang.Runnable({
|
||||
run: func
|
||||
}));
|
||||
}
|
||||
|
||||
export function isMainThread(): Boolean {
|
||||
return android.os.Looper.myLooper() === android.os.Looper.getMainLooper();
|
||||
}
|
||||
10
tns-core-modules/utils/mainthread-helper.d.ts
vendored
Normal file
10
tns-core-modules/utils/mainthread-helper.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* Dispatches the passed function for execution on the main thread
|
||||
* @param func The function to execute on the main thread.
|
||||
*/
|
||||
export function dispatchToMainThread(func: Function);
|
||||
|
||||
/**
|
||||
* @returns Boolean value indicating whether the current thread is the main thread
|
||||
*/
|
||||
export function isMainThread(): boolean
|
||||
7
tns-core-modules/utils/mainthread-helper.ios.ts
Normal file
7
tns-core-modules/utils/mainthread-helper.ios.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export function dispatchToMainThread(func: () => void) {
|
||||
NSOperationQueue.mainQueue.addOperationWithBlock(func);
|
||||
}
|
||||
|
||||
export function isMainThread(): Boolean {
|
||||
return NSThread.isMainThread;
|
||||
}
|
||||
@@ -1,4 +1,7 @@
|
||||
import * as types from "./types";
|
||||
import { dispatchToMainThread, isMainThread } from "./mainthread-helper"
|
||||
|
||||
export * from "./mainthread-helper"
|
||||
|
||||
export const RESOURCE_PREFIX = "res://";
|
||||
export const FILE_PREFIX = "file:///";
|
||||
@@ -154,3 +157,18 @@ export function hasDuplicates(arr: Array<any>): boolean {
|
||||
export function eliminateDuplicates(arr: Array<any>): Array<any> {
|
||||
return Array.from(new Set(arr));
|
||||
}
|
||||
|
||||
export function executeOnMainThread(func: Function) {
|
||||
if (isMainThread()) {
|
||||
return func();
|
||||
} else {
|
||||
dispatchToMainThread(func);
|
||||
}
|
||||
}
|
||||
|
||||
export function mainThreadify(func: Function): (...args: any[]) => void {
|
||||
return function () {
|
||||
const argsToPass = arguments;
|
||||
executeOnMainThread(() => func.apply(this, argsToPass));
|
||||
}
|
||||
}
|
||||
|
||||
18
tns-core-modules/utils/utils.d.ts
vendored
18
tns-core-modules/utils/utils.d.ts
vendored
@@ -4,6 +4,8 @@
|
||||
|
||||
import { dip, px } from "../ui/core/view";
|
||||
|
||||
export * from "./mainthread-helper"
|
||||
|
||||
export const RESOURCE_PREFIX: string;
|
||||
export const FILE_PREFIX: string;
|
||||
|
||||
@@ -269,6 +271,22 @@ export function GC();
|
||||
*/
|
||||
export function releaseNativeObject(object: any /*java.lang.Object | NSObject*/);
|
||||
|
||||
/**
|
||||
* Checks if the current thread is the main thread. Directly calls the passed function
|
||||
* if it is, or dispatches it to the main thread otherwise.
|
||||
* @param func The function to execute on the main thread.
|
||||
*/
|
||||
export function executeOnMainThread(func: Function);
|
||||
|
||||
/**
|
||||
* Returns a function wrapper which executes the supplied function on the main thread.
|
||||
* The wrapper behaves like the original function and passes all of its arguments BUT
|
||||
* discards its return value.
|
||||
* @param func The function to execute on the main thread
|
||||
* @returns The wrapper function which schedules execution to the main thread
|
||||
*/
|
||||
export function mainThreadify(func: Function): (...args: any[]) => void
|
||||
|
||||
/**
|
||||
* Returns true if the specified path points to a resource or local file.
|
||||
* @param path The path.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "tns-platform-declarations",
|
||||
"version": "5.4.0",
|
||||
"version": "6.0.0",
|
||||
"description": "Platform-specific TypeScript declarations for NativeScript for accessing native objects",
|
||||
"main": "",
|
||||
"scripts": {
|
||||
|
||||
0
unit-tests/polyfills/mainthread-helper.ts
Normal file
0
unit-tests/polyfills/mainthread-helper.ts
Normal file
@@ -8,12 +8,13 @@ const tnsCoreModules = path.resolve(__dirname, "..", "tns-core-modules");
|
||||
moduleAlias.addPath(tnsCoreModules);
|
||||
moduleAlias.addAliases({
|
||||
// NOTE: require("tns-core-modules/platform") with these aliases will work in node but fail in Angular AoT
|
||||
// "tns-core-modules/platform": path.resolve(__dirname, "polyfills", "platform"),
|
||||
// "tns-core-modules/file-system/file-system-access": path.resolve(__dirname, "polyfills", "file-system-access"),
|
||||
// "tns-core-modules/utils/utils": path.resolve(tnsCoreModules, "utils/utils-common"),
|
||||
// "tns-core-modules/color": path.resolve(tnsCoreModules, "color/color-common"),
|
||||
// "tns-core-modules/ui/styling/font": path.resolve(tnsCoreModules, "ui/styling/font-common"),
|
||||
// "tns-core-modules/ui/styling/background": path.resolve(tnsCoreModules, "ui/styling/background-common"),
|
||||
"tns-core-modules/platform": path.resolve(__dirname, "polyfills", "platform"),
|
||||
"tns-core-modules/file-system/file-system-access": path.resolve(__dirname, "polyfills", "file-system-access"),
|
||||
"tns-core-modules/utils/utils": path.resolve(tnsCoreModules, "utils/utils-common"),
|
||||
"./mainthread-helper": path.resolve(__dirname, "polyfills", "mainthread-helper"),
|
||||
"tns-core-modules/color": path.resolve(tnsCoreModules, "color/color-common"),
|
||||
"tns-core-modules/ui/styling/font": path.resolve(tnsCoreModules, "ui/styling/font-common"),
|
||||
"tns-core-modules/ui/styling/background": path.resolve(tnsCoreModules, "ui/styling/background-common"),
|
||||
|
||||
"tns-core-modules": tnsCoreModules,
|
||||
"~": __dirname
|
||||
|
||||
Reference in New Issue
Block a user