diff --git a/.travis.yml b/.travis.yml index ab43ba5b1..741790a5d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ env: - NODE_VERSION=8 - EMULATOR_API_LEVEL=23 - ANDROID_VERSION=28 - - ANDROID_BUILD_TOOLS_VERSION=28.0.2 + - ANDROID_BUILD_TOOLS_VERSION=28.0.3 - ANDROID_ABI=armeabi-v7a - EMULATOR_NAME=test - ANDROID_TAG=google_apis diff --git a/CHANGELOG.md b/CHANGELOG.md index ff1265713..4941b0824 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,15 @@ + +## [7.0.1](https://github.com/NativeScript/nativescript-angular/compare/7.0.0...7.0.1) (2018-11-20) + + +### Bug Fixes + +* crash in deactivate page router outlet ([#1590](https://github.com/NativeScript/nativescript-angular/issues/1590)) ([f8c7468](https://github.com/NativeScript/nativescript-angular/commit/f8c7468)) +* **dialogs:** unable to reopen shared modal view when tab as root ([199c245](https://github.com/NativeScript/nativescript-angular/commit/199c245)) +* **location-strategy:** crash when going back on nested named lazy loaded module ([#1618](https://github.com/NativeScript/nativescript-angular/issues/1618)) ([d9ffb83](https://github.com/NativeScript/nativescript-angular/commit/d9ffb83)) + + + # [7.0.0](https://github.com/NativeScript/nativescript-angular/compare/6.2.0...7.0.0) (2018-11-12) diff --git a/e2e/modal-navigation-ng/app/app.android.css b/e2e/modal-navigation-ng/app/app.android.css new file mode 100644 index 000000000..529b4cbd8 --- /dev/null +++ b/e2e/modal-navigation-ng/app/app.android.css @@ -0,0 +1,12 @@ +Button{ + font-size: 8; + margin: 0px; + padding: 0px; + height: 40; +} + +TextView { + font-size: 10; + margin: 0px; + padding: 0px; +} \ No newline at end of file diff --git a/e2e/modal-navigation-ng/app/app.component.ts b/e2e/modal-navigation-ng/app/app.component.ts index 4c61400d7..45decfedf 100644 --- a/e2e/modal-navigation-ng/app/app.component.ts +++ b/e2e/modal-navigation-ng/app/app.component.ts @@ -4,24 +4,47 @@ import { NSLocationStrategy } from "nativescript-angular/router/ns-location-stra import { ViewContainerRefService } from "./shared/ViewContainerRefService"; +import { AppModule } from "./app.module"; +import { ModalDialogOptions, ModalDialogService } from "nativescript-angular"; +import { ModalViewComponent } from "./modal-shared/modal-view.component"; + @Component({ - selector: "ns-app", - templateUrl: "app.component.html", + selector: "ns-app", + templateUrl: "app.component.html" }) - export class AppComponent { - constructor( - router: Router, - location: NSLocationStrategy, - private _vcRef: ViewContainerRef, - private _viewContainerRefService: ViewContainerRefService) { - router.events.subscribe(e => { - if (e instanceof NavigationEnd) { - console.log("[ROUTER]: " + e.toString()); - console.log(location.toString()); - } - }); + constructor( + router: Router, + location: NSLocationStrategy, + private modal: ModalDialogService, + private _vcRef: ViewContainerRef, + private _viewContainerRefService: ViewContainerRefService) { + router.events.subscribe(e => { + if (e instanceof NavigationEnd) { + console.log("[ROUTER]: " + e.toString()); + console.log(location.toString()); + } + }); + + this._viewContainerRefService.root = this._vcRef; + } - this._viewContainerRefService.root = this._vcRef; + ngOnInit() { + if (AppModule.root === "page-router-modal") { + this.onRootModalTap(); + console.log("Page modal page from frame root"); } + } + + onRootModalTap(): void { + const options: ModalDialogOptions = { + viewContainerRef: this._viewContainerRefService.root, + context: {}, + fullscreen: true + }; + + this.modal.showModal(ModalViewComponent, options).then((result: string) => { + console.log(result); + }); + } } diff --git a/e2e/modal-navigation-ng/app/app.css b/e2e/modal-navigation-ng/app/app.css index 5e41a4552..d132e79b9 100644 --- a/e2e/modal-navigation-ng/app/app.css +++ b/e2e/modal-navigation-ng/app/app.css @@ -9,7 +9,6 @@ In many cases you may want to use the NativeScript core theme instead of writing your own CSS rules. For a full list of class names in the theme refer to http://docs.nativescript.org/ui/theme. */ -@import '~nativescript-theme-core/css/core.light.css'; Button { font-size: 10px; -} +} \ No newline at end of file diff --git a/e2e/modal-navigation-ng/app/app.ios.css b/e2e/modal-navigation-ng/app/app.ios.css new file mode 100644 index 000000000..16f77c1ba --- /dev/null +++ b/e2e/modal-navigation-ng/app/app.ios.css @@ -0,0 +1,12 @@ +#home-page { + font-size: 10; + margin: 0px; + padding: 0px; +} +#home-page Button { + margin-bottom: 20px; + padding: 20px; + border-color: gray; + border-width: 2px; + border-radius: 8px; +} \ No newline at end of file diff --git a/e2e/modal-navigation-ng/app/app.module.ts b/e2e/modal-navigation-ng/app/app.module.ts index 9251b6661..b868bf401 100644 --- a/e2e/modal-navigation-ng/app/app.module.ts +++ b/e2e/modal-navigation-ng/app/app.module.ts @@ -7,6 +7,8 @@ import { TabComponent } from "./tab.component"; import { LayoutComponent } from "./layout.component"; import { HomeComponent } from "./home/home.component"; +import { RootSectionComponent } from "./navigation/root.section.component"; +import { BasicsNavigationComponent } from "./navigation/basic.navigation.component"; import { SecondComponent } from "./second/second.component"; import { ModalSecondComponent } from "./modal-second/modal-second.component"; import { ModalComponent } from "./modal/modal.component"; @@ -44,6 +46,8 @@ traceEnable(); NamedRouterComponent, TabComponent, LayoutComponent, + RootSectionComponent, + BasicsNavigationComponent, HomeComponent, SecondComponent, ModalComponent, @@ -78,9 +82,13 @@ export class AppModule { static bootstrapRootComponent() { const options = { 'page-router': AppComponent, + 'page-router-modal': AppComponent, 'named-page-router': NamedRouterComponent, + 'named-page-router-modal': NamedRouterComponent, 'tab': TabComponent, - 'layout': LayoutComponent + 'tab-modal': TabComponent, + 'layout': LayoutComponent, + 'layout-modal': LayoutComponent, }; const component = options[AppModule.root]; diff --git a/e2e/modal-navigation-ng/app/app.routing.ts b/e2e/modal-navigation-ng/app/app.routing.ts index 0a49e8251..263f4a1b1 100644 --- a/e2e/modal-navigation-ng/app/app.routing.ts +++ b/e2e/modal-navigation-ng/app/app.routing.ts @@ -102,6 +102,12 @@ const routesTab: Routes = [ path: "modal-second", component: ModalSecondComponent } ] + }, + { + path: "modal-shared", component: ModalViewContentComponent, outlet: "modalOutlet" + }, + { + path: "modal-shared-second-host", component: ModalSharedSecondComponent } ]; @@ -110,23 +116,28 @@ const routesLayout: Routes = [ path: "modal", component: ModalComponent, children: [ { path: "nested-frame-modal", component: NestedModalComponent }] }, - { path: "modal-second", component: ModalSecondComponent } + { path: "modal-second", component: ModalSecondComponent }, + { + path: "modal-shared", component: ModalViewContentComponent, outlet: "modalOutlet" + }, + { + path: "modal-shared-second-host", component: ModalSharedSecondComponent + } ] - @NgModule({ imports: [NativeScriptRouterModule.forRoot(routes)], exports: [NativeScriptRouterModule] }) export class AppRoutingModule { constructor(private router: Router) { - if (AppModule.root === "page-router") { + if (AppModule.root === "page-router" || AppModule.root === "page-router-modal") { this.router.resetConfig(routes); - } else if (AppModule.root === "layout") { + } else if (AppModule.root === "layout" || AppModule.root === "layout-modal") { this.router.resetConfig(routesLayout); - } else if (AppModule.root === "named-page-router") { + } else if (AppModule.root === "named-page-router" || AppModule.root === "named-page-router-modal") { this.router.resetConfig(namedOutletRoutes); - } else { + } else if(AppModule.root === "tab" || AppModule.root === "tab-modal"){ this.router.resetConfig(routesTab); } } diff --git a/e2e/modal-navigation-ng/app/home/home.component.html b/e2e/modal-navigation-ng/app/home/home.component.html index a632c3a92..89de6c594 100644 --- a/e2e/modal-navigation-ng/app/home/home.component.html +++ b/e2e/modal-navigation-ng/app/home/home.component.html @@ -1,17 +1,14 @@ - - + + - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + \ No newline at end of file diff --git a/e2e/modal-navigation-ng/app/home/home.component.ts b/e2e/modal-navigation-ng/app/home/home.component.ts index e0a58f50e..72e8f889e 100644 --- a/e2e/modal-navigation-ng/app/home/home.component.ts +++ b/e2e/modal-navigation-ng/app/home/home.component.ts @@ -12,93 +12,22 @@ import { confirm } from "tns-core-modules/ui/dialogs"; import { AppModule } from "../app.module"; @Component({ - moduleId: module.id, - selector: "home-page", - templateUrl: "./home.component.html" + moduleId: module.id, + selector: "home-page", + templateUrl: "./home.component.html" }) export class HomeComponent { - constructor( - private modal: ModalDialogService, - private vcRef: ViewContainerRef, - private viewContainerRefService: ViewContainerRefService, - private routerExtension: RouterExtensions) { } - - onModalNoFrame() { - const options: ModalDialogOptions = { - context: { - navigationVisibility: false - }, - fullscreen: true, - viewContainerRef: this.vcRef - }; - - this.modal.showModal(ModalComponent, options).then((res: string) => { - console.log("moda-no-frame closed"); - }); - } - - onModalFrame() { - const options: ModalDialogOptions = { - context: { - navigationVisibility: true, - modalRoute: "modal" - }, - fullscreen: true, - viewContainerRef: this.vcRef - }; - - this.modal.showModal(ModalRouterComponent, options).then((res: string) => { - console.log("moda-frame closed"); - }); - } - - onNavigateSecond() { - this.routerExtension.navigate(["second"]); - } - - onFrameRootViewReset() { - AppModule.root = "page-router"; - AppModule.platformRef._livesync(); - } - - onNamedFrameRootViewReset() { - AppModule.root = "named-page-router"; - AppModule.platformRef._livesync(); - } - - onTabRootViewReset() { - AppModule.root = "tab"; - AppModule.platformRef._livesync(); - } - - onLayoutRootViewReset() { - AppModule.root = "layout"; - AppModule.platformRef._livesync(); - } - - onRootModalTap(): void { - const options: ModalDialogOptions = { - viewContainerRef: this.viewContainerRefService.root, - context: {}, - fullscreen: true - }; - - this.modal.showModal(ModalViewComponent, options) - .then((result: string) => { - console.log(result); - }); - } - - onShowDialog() { - let options = { - title: "Dialog", - message: "Message", - okButtonText: "Yes", - cancelButtonText: "No" - } - - confirm(options).then((result: boolean) => { - console.log(result); - }) - } + constructor( + private modal: ModalDialogService, + private vcRef: ViewContainerRef, + private viewContainerRefService: ViewContainerRefService, + private routerExtension: RouterExtensions) { } + + onNavigateSecond() { + this.routerExtension.navigate(["second"]); + } + + onNavigateSecondWithOutlet() { + this.routerExtension.navigate([ { outlets: { namedRouter:["second"] } }]); + } } diff --git a/e2e/modal-navigation-ng/app/layout.component.html b/e2e/modal-navigation-ng/app/layout.component.html index 3d50caa77..c512f39e2 100644 --- a/e2e/modal-navigation-ng/app/layout.component.html +++ b/e2e/modal-navigation-ng/app/layout.component.html @@ -1,10 +1,4 @@ - - - - - - - - - - \ No newline at end of file + + + + \ No newline at end of file diff --git a/e2e/modal-navigation-ng/app/layout.component.ts b/e2e/modal-navigation-ng/app/layout.component.ts index 223e4dcdd..fe6ee9a9d 100644 --- a/e2e/modal-navigation-ng/app/layout.component.ts +++ b/e2e/modal-navigation-ng/app/layout.component.ts @@ -2,14 +2,9 @@ import { Component, ViewContainerRef } from "@angular/core"; import { Router, NavigationEnd } from "@angular/router"; import { NSLocationStrategy } from "nativescript-angular/router/ns-location-strategy"; import { ModalDialogService, ModalDialogOptions } from "nativescript-angular/directives/dialogs"; -import { ModalComponent } from "./modal/modal.component"; import { ModalViewComponent } from "./modal-shared/modal-view.component"; -import { ModalRouterComponent } from "./modal/modal-router/modal-router.component"; -import { confirm } from "tns-core-modules/ui/dialogs"; - -import { AppModule } from "./app.module"; - import { ViewContainerRefService } from "./shared/ViewContainerRefService"; +import { AppModule } from "./app.module"; @Component({ selector: "ns-layout", @@ -22,76 +17,33 @@ export class LayoutComponent { private router: Router, private location: NSLocationStrategy, private vcRef: ViewContainerRef, - private _viewContainerRefService: ViewContainerRefService) { - router.events.subscribe(e => { + private viewContainerRefService: ViewContainerRefService) { + this.router.events.subscribe(e => { if (e instanceof NavigationEnd) { console.log("[ROUTER]: " + e.toString()); - console.log(location.toString()); + console.log(this.location.toString()); } }); - this._viewContainerRefService.root = this.vcRef; + this.viewContainerRefService.root = this.vcRef; } - onModalNoFrame() { - const options: ModalDialogOptions = { - context: { - navigationVisibility: false - }, - fullscreen: true, - viewContainerRef: this.vcRef - }; - - this.modal.showModal(ModalComponent, options).then((res: string) => { - console.log("moda-no-frame closed"); - }); - } - - onModalFrame() { - const options: ModalDialogOptions = { - context: { - navigationVisibility: true, - modalRoute: "modal" - }, - fullscreen: true, - viewContainerRef: this.vcRef - }; - - this.modal.showModal(ModalRouterComponent, options).then((res: string) => { - console.log("moda-frame closed"); - }); - } - - onFrameRootViewReset() { - AppModule.root = "page-router"; - AppModule.platformRef._livesync(); - } - - onNamedFrameRootViewReset() { - AppModule.root = "named-page-router"; - AppModule.platformRef._livesync(); - } - - onTabRootViewReset() { - AppModule.root = "tab"; - AppModule.platformRef._livesync(); + ngOnInit() { + if (AppModule.root === "layout-modal") { + console.log("Show modal page from tab root view!"); + this.onRootModalTap(); + } } - onLayoutRootViewReset() { - AppModule.root = "layout"; - AppModule.platformRef._livesync(); - } + onRootModalTap(): void { + const options: ModalDialogOptions = { + viewContainerRef: this.viewContainerRefService.root, + context: {}, + fullscreen: true + }; - onShowDialog() { - let options = { - title: "Dialog", - message: "Message", - okButtonText: "Yes", - cancelButtonText: "No" - } - - confirm(options).then((result: boolean) => { - console.log(result); - }) - } + this.modal.showModal(ModalViewComponent, options).then((result: string) => { + console.log(result); + }); + } } diff --git a/e2e/modal-navigation-ng/app/modal-shared/modal-shared-second.component.ts b/e2e/modal-navigation-ng/app/modal-shared/modal-shared-second.component.ts index 6f9c5ca21..26e1b7bcc 100644 --- a/e2e/modal-navigation-ng/app/modal-shared/modal-shared-second.component.ts +++ b/e2e/modal-navigation-ng/app/modal-shared/modal-shared-second.component.ts @@ -10,7 +10,7 @@ import { RouterExtensions } from "nativescript-angular/router"; moduleId: module.id, template: ` - + @@ -25,9 +25,9 @@ export class ModalSharedSecondComponent { onRootModalTap(): void { const options: ModalDialogOptions = { - viewContainerRef: this._viewContainerRefService.root, context: {}, - fullscreen: true + fullscreen: true, + viewContainerRef: this._viewContainerRefService.root, }; this._modalService.showModal(ModalViewComponent, options) diff --git a/e2e/modal-navigation-ng/app/modal-shared/modal-view-content.component.ts b/e2e/modal-navigation-ng/app/modal-shared/modal-view-content.component.ts index 30247073c..f194354bf 100644 --- a/e2e/modal-navigation-ng/app/modal-shared/modal-view-content.component.ts +++ b/e2e/modal-navigation-ng/app/modal-shared/modal-view-content.component.ts @@ -9,7 +9,7 @@ import { ModalDialogParams } from "nativescript-angular/modal-dialog"; - + `, styles: [` diff --git a/e2e/modal-navigation-ng/app/modal/modal-router/modal-router.component.ts b/e2e/modal-navigation-ng/app/modal/modal-router/modal-router.component.ts index 26e40b992..268235e5b 100644 --- a/e2e/modal-navigation-ng/app/modal/modal-router/modal-router.component.ts +++ b/e2e/modal-navigation-ng/app/modal/modal-router/modal-router.component.ts @@ -18,6 +18,5 @@ export class ModalRouterComponent implements OnInit { ngOnInit() { this.routerExtension.navigate([this.modalRoute], { relativeTo: this.activeRoute }); - //this.routerExtension.navigate([ { outlets: { modalOutlet: [this.modalRoute] } }], { relativeTo: this.activeRoute }); } } diff --git a/e2e/modal-navigation-ng/app/named-router.component.ts b/e2e/modal-navigation-ng/app/named-router.component.ts index e00c929a3..745ed6f11 100644 --- a/e2e/modal-navigation-ng/app/named-router.component.ts +++ b/e2e/modal-navigation-ng/app/named-router.component.ts @@ -3,25 +3,48 @@ import { Router, NavigationEnd } from "@angular/router"; import { NSLocationStrategy } from "nativescript-angular/router/ns-location-strategy"; import { ViewContainerRefService } from "./shared/ViewContainerRefService"; +import { AppModule } from "./app.module"; +import { ModalDialogOptions, ModalDialogService } from "nativescript-angular"; +import { ModalViewComponent } from "./modal-shared/modal-view.component"; @Component({ - selector: "named-router", - templateUrl: "named-router.component.html", + selector: "named-router", + templateUrl: "named-router.component.html" }) - export class NamedRouterComponent { - constructor( - router: Router, - location: NSLocationStrategy, - private _vcRef: ViewContainerRef, - private _viewContainerRefService: ViewContainerRefService) { - router.events.subscribe(e => { - if (e instanceof NavigationEnd) { - console.log("[ROUTER]: " + e.toString()); - console.log(location.toString()); - } - }); + constructor( + router: Router, + location: NSLocationStrategy, + private modal: ModalDialogService, + private _vcRef: ViewContainerRef, + private _viewContainerRefService: ViewContainerRefService + ) { + router.events.subscribe(e => { + if (e instanceof NavigationEnd) { + console.log("[ROUTER]: " + e.toString()); + console.log(location.toString()); + } + }); + + this._viewContainerRefService.root = this._vcRef; + } - this._viewContainerRefService.root = this._vcRef; + ngOnInit() { + if (AppModule.root === "named-page-router-modal") { + console.log("Show modal page from tab root view!"); + this.onRootModalTap(); } + } + + onRootModalTap(): void { + const options: ModalDialogOptions = { + viewContainerRef: this._viewContainerRefService.root, + context: {}, + fullscreen: true + }; + + this.modal.showModal(ModalViewComponent, options).then((result: string) => { + console.log(result); + }); + } } diff --git a/e2e/modal-navigation-ng/app/navigation/basic.navigation.component.ts b/e2e/modal-navigation-ng/app/navigation/basic.navigation.component.ts new file mode 100644 index 000000000..54c818612 --- /dev/null +++ b/e2e/modal-navigation-ng/app/navigation/basic.navigation.component.ts @@ -0,0 +1,87 @@ +import { Component, ViewContainerRef, Input } from "@angular/core"; +import { Router, NavigationEnd } from "@angular/router"; +import { ModalDialogService, ModalDialogOptions } from "nativescript-angular/directives/dialogs"; +import { ModalComponent } from "../modal/modal.component"; +import { ModalRouterComponent } from "../modal/modal-router/modal-router.component"; +import { confirm } from "tns-core-modules/ui/dialogs"; + +import { ViewContainerRefService } from "../shared/ViewContainerRefService"; +import { ModalViewComponent } from "~/modal-shared/modal-view.component"; + +@Component({ + selector: "basic-nav", + template: ` + + + + + + +` +}) + +export class BasicsNavigationComponent { + + @Input() col: number; + constructor( + private modal: ModalDialogService, + private router: Router, + private vcf: ViewContainerRef, + private viewContainerRefService: ViewContainerRefService) { + } + + onModalNoFrame() { + const options: ModalDialogOptions = { + context: { + navigationVisibility: false + }, + fullscreen: true, + viewContainerRef: this.vcf + }; + + this.modal.showModal(ModalComponent, options).then((res: string) => { + console.log("modal-no-frame closed"); + }); + } + + onModalFrame() { + const options: ModalDialogOptions = { + context: { + navigationVisibility: true, + modalRoute: "modal" + }, + fullscreen: true, + viewContainerRef: this.vcf + }; + + this.modal.showModal(ModalRouterComponent, options).then((res: string) => { + console.log("modal-frame closed"); + }); + } + + onShowDialog() { + let options = { + title: "Dialog", + message: "Message", + okButtonText: "Yes", + cancelButtonText: "No" + } + + confirm(options).then((result: boolean) => { + console.log(result); + }) + } + + onRootModalTap(): void { + const options: ModalDialogOptions = { + viewContainerRef: this.viewContainerRefService.root, + context: {}, + fullscreen: true + }; + + this.modal.showModal(ModalViewComponent, options) + .then((result: string) => { + console.log(result); + }); + } +} diff --git a/e2e/modal-navigation-ng/app/navigation/root.section.component.html b/e2e/modal-navigation-ng/app/navigation/root.section.component.html new file mode 100644 index 000000000..2a5bf9b84 --- /dev/null +++ b/e2e/modal-navigation-ng/app/navigation/root.section.component.html @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/e2e/modal-navigation-ng/app/navigation/root.section.component.ts b/e2e/modal-navigation-ng/app/navigation/root.section.component.ts new file mode 100644 index 000000000..a6f1b360d --- /dev/null +++ b/e2e/modal-navigation-ng/app/navigation/root.section.component.ts @@ -0,0 +1,31 @@ +import { Component } from "@angular/core"; +import { AppModule } from "../app.module"; + +@Component({ + moduleId: module.id, + selector: "root-section", + templateUrl: "./root.section.component.html" +}) +export class RootSectionComponent { + constructor() { } + + onFrameRootViewReset(showModal) { + AppModule.root = showModal ? "page-router-modal" : "page-router"; + AppModule.platformRef._livesync(); + } + + onNamedFrameRootViewReset(showModal) { + AppModule.root = showModal ? "named-page-router-modal" : "named-page-router"; + AppModule.platformRef._livesync(); + } + + onTabRootViewReset(showModal) { + AppModule.root = showModal ? "tab-modal" : "tab"; + AppModule.platformRef._livesync(); + } + + onLayoutRootViewReset(showModal) { + AppModule.root = showModal ? "layout-modal" : "layout"; + AppModule.platformRef._livesync(); + } +} diff --git a/e2e/modal-navigation-ng/app/tab.component.ts b/e2e/modal-navigation-ng/app/tab.component.ts index 04d081d4f..b72c056dc 100644 --- a/e2e/modal-navigation-ng/app/tab.component.ts +++ b/e2e/modal-navigation-ng/app/tab.component.ts @@ -1,12 +1,49 @@ -import { Component, OnInit } from "@angular/core"; +import { Component, ViewContainerRef } from "@angular/core"; import { Router, NavigationEnd } from "@angular/router"; -import { RouterExtensions } from "nativescript-angular/router"; +import { NSLocationStrategy } from "nativescript-angular/router/ns-location-strategy"; + +import { ViewContainerRefService } from "./shared/ViewContainerRefService"; +import { AppModule } from "./app.module"; +import { ModalDialogOptions, ModalDialogService } from "nativescript-angular"; +import { ModalViewComponent } from "./modal-shared/modal-view.component"; @Component({ - selector: "ns-tab", - templateUrl: "tab.component.html", + selector: "ns-tab", + templateUrl: "tab.component.html", }) - export class TabComponent { - constructor(private routerExtension: RouterExtensions) { } + constructor( + router: Router, + location: NSLocationStrategy, + private _vcRef: ViewContainerRef, + private _viewContainerRefService: ViewContainerRefService, + private modal: ModalDialogService) { + router.events.subscribe(e => { + if (e instanceof NavigationEnd) { + console.log("[ROUTER]: " + e.toString()); + console.log(location.toString()); + } + }); + + this._viewContainerRefService.root = this._vcRef; + } + + ngOnInit() { + if (AppModule.root === "tab-modal") { + console.log("Show modal page from tab root view!"); + this.onRootModalTap(); + } + } + + onRootModalTap(): void { + const options: ModalDialogOptions = { + viewContainerRef: this._viewContainerRefService.root, + context: {}, + fullscreen: true + }; + + this.modal.showModal(ModalViewComponent, options).then((result: string) => { + console.log(result); + }); + } } diff --git a/e2e/modal-navigation-ng/e2e/modal-frame.e2e-spec.ts b/e2e/modal-navigation-ng/e2e/modal-frame.e2e-spec.ts index c26ee077c..d5de6c2bb 100644 --- a/e2e/modal-navigation-ng/e2e/modal-frame.e2e-spec.ts +++ b/e2e/modal-navigation-ng/e2e/modal-frame.e2e-spec.ts @@ -1,5 +1,5 @@ import { AppiumDriver, createDriver } from "nativescript-dev-appium"; -import { Screen } from "./screen" +import { Screen } from "./screens/screen" import { roots, modalFrameBackground, @@ -8,7 +8,7 @@ import { testNestedModalFrameBackground, testNestedModalPageBackground, testDialogBackground -} from "./shared.e2e-spec" +} from "./screens/shared-screen" describe("modal-frame:", () => { diff --git a/e2e/modal-navigation-ng/e2e/modal-layout.e2e-spec.ts b/e2e/modal-navigation-ng/e2e/modal-layout.e2e-spec.ts index 5cb412226..b518f1a95 100644 --- a/e2e/modal-navigation-ng/e2e/modal-layout.e2e-spec.ts +++ b/e2e/modal-navigation-ng/e2e/modal-layout.e2e-spec.ts @@ -1,10 +1,10 @@ import { AppiumDriver, createDriver } from "nativescript-dev-appium"; -import { Screen } from "./screen" +import { Screen } from "./screens/screen" import { roots, testNestedModalPageBackground, testDialogBackground, -} from "./shared.e2e-spec" +} from "./screens/shared-screen" describe("modal-layout:", () => { diff --git a/e2e/modal-navigation-ng/e2e/modal-on-init.e2e-spec.ts b/e2e/modal-navigation-ng/e2e/modal-on-init.e2e-spec.ts new file mode 100644 index 000000000..394fa5d49 --- /dev/null +++ b/e2e/modal-navigation-ng/e2e/modal-on-init.e2e-spec.ts @@ -0,0 +1,156 @@ +import { AppiumDriver, createDriver } from "nativescript-dev-appium"; +import { Screen, sharedModalView, homeComponent } from "./screens/screen"; +import { + assertComponent, + goBack, + navigateToSecondComponent +} from "./screens/shared-screen"; + +const roots = [ + "setTabRootViewModal", + "setFrameRootViewModal", + "setNamedFrameRootViewModal", +]; + +describe("modal-on-init:", () => { + let driver: AppiumDriver; + let screen: Screen; + + before(async () => { + driver = await createDriver(); + screen = new Screen(driver); + }); + + after("modal-on-init after all hook", async () => { + await driver.logTestArtifacts("modal-on-init"); + }); + + roots.forEach(root => { + describe("Shared Modal on Init", () => { + before(async () => { + await screen[root](); + console.log(`Root: ${root}`); + }); + + beforeEach(async function() {}); + + afterEach(async function() { + if (this.currentTest.state === "failed") { + await driver.logTestArtifacts(this.currentTest.title); + await driver.resetApp(); + await screen[root](); + } + }); + + after("root after all hook", async function() { + await driver.logTestArtifacts(`${root}_root_after_all_hook`); + }); + + it("should shared modal view", async () => { + await assertComponent(driver, sharedModalView); + }); + + it("run in background", async () => { + await driver.backgroundApp(1); + await assertComponent(driver, sharedModalView); + }); + + it("should close shared modal ", async () => { + await screen.closeModal(); + await screen.loadedHome(); + }); + + it("should open/close shared modal", async () => { + await screen.loadSharedModal(true); + await screen.closeModal(); + await screen.loadedHome(); + }); + + it("should open/close shared modal again", async () => { + await screen.loadSharedModal(true); + if (driver.isAndroid) { + await driver.navBack(); + }else{ + await screen.closeModal(); + } + await screen.loadedHome(); + }); + + it("should open/close modal with frame", async () => { + await screen.loadModalFrame(true); + await screen.closeModal(); + }); + + it("should open/close shared modal again", async () => { + await screen.loadSharedModal(true); + await screen.closeModal(); + }); + + it("run in background again", async () => { + await driver.backgroundApp(1); + await screen.loadedHome(); + }); + + it("should open/close shared modal second", async () => { + await screen.loadModalFrame(true); + await screen.closeModal(); + }); + }); + }); + + describe("Shared Modal on Init", () => { + const root = "setLayoutRootViewModal"; + before(async () => { + await screen[root](); + console.log(`Root: ${root}`); + }); + + beforeEach(async function() {}); + + afterEach(async function() { + if (this.currentTest.state === "failed") { + await driver.logTestArtifacts(this.currentTest.title); + await driver.resetApp(); + await screen[root](); + } + }); + + after("root after all hook", async function() { + await driver.logTestArtifacts(`${root}_root_after_all_hook`); + }); + + it("should shared modal view", async () => { + await assertComponent(driver, sharedModalView); + }); + + it("run in background", async () => { + await driver.backgroundApp(1); + await assertComponent(driver, sharedModalView); + }); + + it("should close shared modal ", async () => { + await screen.closeModal(); + await screen.loadedHome(); + }); + + it("should open/close shared modal", async () => { + await screen.loadModalFrame(true); + await screen.closeModal(); + }); + + it("run in background again", async () => { + await driver.backgroundApp(1); + await screen.loadedHome(); + }); + + it("should open/close shared modal second", async () => { + await screen.loadModalFrame(true); + await screen.closeModal(); + }); + + it("should open/close shared modal", async () => { + await screen.loadSharedModal(true); + await screen.closeModal(); + }); + }); +}); diff --git a/e2e/modal-navigation-ng/e2e/modal.shared.e2e-spec.ts b/e2e/modal-navigation-ng/e2e/modal.shared.e2e-spec.ts index cbeafec35..fd76f81eb 100644 --- a/e2e/modal-navigation-ng/e2e/modal.shared.e2e-spec.ts +++ b/e2e/modal-navigation-ng/e2e/modal.shared.e2e-spec.ts @@ -1,163 +1,151 @@ -import { AppiumDriver, createDriver, SearchOptions } from "nativescript-dev-appium"; -import { assert } from "chai"; +import { AppiumDriver, createDriver } from "nativescript-dev-appium"; +import { Screen } from "./screens/screen" +import { assertComponent, goBack, navigateToSecondComponent } from "./screens/shared-screen"; const homeComponent = "Home Component"; +const roots = ["setFrameRootView", "setTabRootView"]; -describe("Shared modal from home and back", () => { +describe("modal-shared:", () => { let driver: AppiumDriver; + let screen: Screen; before(async () => { driver = await createDriver(); - await driver.resetApp(); - }); - - afterEach(async function () { - if (this.currentTest.state === "failed") { - await driver.logTestArtifacts(this.currentTest.title); - } - }); - - it ("should find home component", async () => { - await assertComponent(driver, homeComponent); - }); - - it("should open/close shared modal from home component", async () => { - await openModal(driver); - await closeModal(driver); - }); - - it ("should find home component again", async () => { - await assertComponent(driver, homeComponent); - }); -}); - -describe("Shared modal from second and back", () => { - let driver: AppiumDriver; - - before(async () => { - driver = await createDriver(); - await driver.resetApp(); - }); - - after(async () => { - await driver.quit(); - console.log("Quit driver!"); - }); - - afterEach(async function () { - if (this.currentTest.state === "failed") { - await driver.logPageSource(this.currentTest.title); - await driver.logScreenshot(this.currentTest.title); - } - }); - - it ("should find home component", async () => { - await assertComponent(driver, homeComponent); - }); - - it ("should navigate to second component", async() => { - await navigateToSecondComponent(driver); - }); - - it ("should find second component", async () => { - await assertComponent(driver, "second component"); - }); - - it("should open/close shared modal from second component", async () => { - await openModal(driver); - await closeModal(driver); - }); - - it ("should find second component again", async () => { - await assertComponent(driver, "second component"); - }); -}); - -describe("Shared modal from different components", () => { - let driver: AppiumDriver; - - before(async () => { - driver = await createDriver(); - await driver.resetApp(); - }); - - after(async () => { - await driver.quit(); - console.log("Quit driver!"); - }); - - afterEach(async function () { - if (this.currentTest.state === "failed") { - await driver.logTestArtifacts(this.currentTest.title); - } - }); - - it ("should find home component", async () => { - await assertComponent(driver, homeComponent); - }); - - it("should open/close shared modal from home component", async () => { - await openModal(driver); - await closeModal(driver); - }); - - it ("should find home component again", async () => { - await assertComponent(driver, homeComponent); - }); - - it ("should navigate to second component", async() => { - await navigateToSecondComponent(driver); - }); - - it ("should find second component", async () => { - await assertComponent(driver, "second component"); - }); - - it("should open/close shared modal from second component", async () => { - await openModal(driver); - await closeModal(driver); - }); - - it ("should find second component again", async () => { - await assertComponent(driver, "second component"); - }); - - it ("should navigate back to home component", async () => { - await goBack(driver); - await assertComponent(driver, homeComponent); - }); - - it("should open/close shared modal from home component after manipulations with second", async () => { - await openModal(driver); - await closeModal(driver); - }); - - it ("should find home component again", async () => { - await assertComponent(driver, homeComponent); + screen = new Screen(driver); + }); + + roots.forEach(root => { + describe("Shared modal from second and back", () => { + + before(async () => { + await screen[root](); + }); + + beforeEach(async function () { + }); + + afterEach(async function () { + if (this.currentTest.state === "failed") { + await driver.logTestArtifacts(this.currentTest.title); + await driver.resetApp(); + await screen[root](); + } + }); + + it("should find home component", async () => { + await assertComponent(driver, homeComponent); + }); + + it("should open/close shared modal from home component", async () => { + await screen.loadSharedModal(true); + await screen.closeModal(); + }); + + it("should open/close shared modal from home component again", async () => { + await screen.loadSharedModal(true); + await screen.closeModal(); + }); + + it("should find home component again", async () => { + await screen.loadedHome(); + }); + + it("should navigate to second component", async () => { + await navigateToSecondComponent(driver); + }); + + it("should find second component", async () => { + await assertComponent(driver, "second component"); + }); + + it("should open/close shared modal from second component", async () => { + await screen.loadSharedModal(true); + await screen.closeModal(); + }); + + it("should find second component again", async () => { + await assertComponent(driver, "second component"); + }); + + it("should navigate back to home component", async () => { + await goBack(driver); + await assertComponent(driver, homeComponent); + }); + }); + }); + + describe("modal-shared-different-component:", () => { + let driver: AppiumDriver; + let screen: Screen; + + before(async () => { + driver = await createDriver(); + screen = new Screen(driver); + }); + + roots.forEach(root => { + describe("Shared modal from different components", () => { + before(async () => { + driver = await createDriver(); + await driver.resetApp(); + }); + + after(async () => { + await driver.quit(); + console.log("Quit driver!"); + }); + + afterEach(async function () { + if (this.currentTest.state === "failed") { + await driver.logTestArtifacts(this.currentTest.title); + } + }); + + it("should find home component", async () => { + await screen.loadedHome(); + }); + + it("should open/close shared modal from home component", async () => { + await screen.loadSharedModal(true); + await screen.closeModal(); + }); + + it("should find home component again", async () => { + await screen.loadedHome(); + }); + + it("should navigate to second component", async () => { + await navigateToSecondComponent(driver); + }); + + it("should find second component", async () => { + await assertComponent(driver, "second component"); + }); + + it("should open/close shared modal from second component", async () => { + await screen.loadSharedModal(true); + await screen.closeModal(); + }); + + it("should find second component again", async () => { + await assertComponent(driver, "second component"); + }); + + it("should navigate back to home component", async () => { + await goBack(driver); + await screen.loadedHome(); + }); + + it("should open/close shared modal from home component after manipulations with second", async () => { + await screen.loadSharedModal(true); + await screen.closeModal(); + }); + + it("should find home component again", async () => { + await screen.loadedHome(); + }); + }); + }); }); }); -async function assertComponent(driver: AppiumDriver, message: string) { - const lbl = await driver.findElementByText(message, SearchOptions.exact); - assert.isTrue(await lbl.isDisplayed()); -} - -async function navigateToSecondComponent(driver: AppiumDriver) { - const navigateBtnTap = await driver.findElementByText("go to second (to open shared modal)", SearchOptions.exact); - await navigateBtnTap.click(); -} - -async function openModal(driver: AppiumDriver) { - const btnTap = await driver.findElementByText("show shared modal", SearchOptions.exact); - await btnTap.click(); -} - -async function closeModal(driver: AppiumDriver) { - const closeBtnTap = await driver.findElementByText("close modal", SearchOptions.exact); - await closeBtnTap.click(); -} - -async function goBack(driver: AppiumDriver) { - const backBtnTap = await driver.findElementByText("go back", SearchOptions.exact); - await backBtnTap.click(); -} diff --git a/e2e/modal-navigation-ng/e2e/screen.ts b/e2e/modal-navigation-ng/e2e/screens/screen.ts similarity index 80% rename from e2e/modal-navigation-ng/e2e/screen.ts rename to e2e/modal-navigation-ng/e2e/screens/screen.ts index 0fdbcb183..d45ad05bc 100644 --- a/e2e/modal-navigation-ng/e2e/screen.ts +++ b/e2e/modal-navigation-ng/e2e/screens/screen.ts @@ -16,9 +16,13 @@ const modalTabView = "Show Modal TabView"; const navToSecondPage = "Navigate To Second Page"; const showDialog = "Show Dialog"; const resetFrameRootView = "Reset Frame Root View"; +const resetFrameRootViewModal = "Reset Frame Root View Modal"; const resetNamedFrameRootView = "Reset Named Frame Root View"; +const resetNamedFrameRootViewModal = "Reset Named Frame Root View Modal"; const resetTabRootView = "Reset Tab Root View"; +const resetTabRootViewModal = "Reset Tab Root View Modal"; const resetLayoutRootView = "Reset Layout Root View"; +const resetLayoutRootViewModal = "Reset Layout Root View Modal"; const showNestedModalFrame = "Show Nested Modal Page With Frame"; const showNestedModalPage = "Show Nested Modal Page"; @@ -28,6 +32,8 @@ const confirmDialogMessage = "Message"; const closeModalNested = "Close Modal Nested"; const closeModal = "Close Modal"; const goBack = "Go Back(activatedRoute)"; +export const sharedModalView = "SHARED MODAL VIEW"; +export const homeComponent = "Home Component"; export class Screen { @@ -66,6 +72,26 @@ export class Screen { await btnResetTabRootView.tap(); } + resetTabRootViewModal = async () => { + const btnResetTabRootViewModal = await this._driver.findElementByAutomationText(resetTabRootViewModal); + await btnResetTabRootViewModal.click(); + } + + resetFrameRootViewModal = async () => { + const btnResetTabRootViewModal = await this._driver.findElementByAutomationText(resetFrameRootViewModal); + await btnResetTabRootViewModal.click(); + } + + resetNamedFrameRootViewModal = async () => { + const btnResetTabRootViewModal = await this._driver.findElementByAutomationText(resetNamedFrameRootViewModal); + await btnResetTabRootViewModal.click(); + } + + resetLayoutRootViewModal = async () => { + const btnResetTabRootViewModal = await this._driver.findElementByAutomationText(resetLayoutRootViewModal); + await btnResetTabRootViewModal.click(); + } + loadedTabRootView = async () => { const tabFirst = await this._driver.findElementByAutomationText(first); assert.isTrue(await tabFirst.isDisplayed()); @@ -97,6 +123,26 @@ export class Screen { await this.resetLayoutRootView(); } + setTabRootViewModal = async () => { + await this.loadedHome(); + await this.resetTabRootViewModal(); + } + + setFrameRootViewModal = async () => { + await this.loadedHome(); + await this.resetFrameRootViewModal(); + } + + setNamedFrameRootViewModal = async () => { + await this.loadedHome(); + await this.resetNamedFrameRootViewModal(); + } + + setLayoutRootViewModal = async () => { + await this.loadedHome(); + await this.resetLayoutRootViewModal(); + } + showModalFrame = async () => { const btnModalFrame = await this._driver.findElementByAutomationText(modalFrame); await btnModalFrame.tap(); @@ -113,6 +159,12 @@ export class Screen { await btnModalPage.tap(); } + + private showSharedModal = async () => { + const btnTap = await this._driver.waitForElement("Show Shared Modal"); + await btnTap.click(); + } + loadedModalPage = async () => { const btnShowNestedModalPage = await this._driver.findElementByAutomationText(showNestedModalPage); assert.isTrue(await btnShowNestedModalPage.isDisplayed(), `${showNestedModalPage} is not displayed`); @@ -230,7 +282,7 @@ export class Screen { closeModal = async () => { const btnCloseModal = await this._driver.waitForElement(closeModal, 10000); - await btnCloseModal.tap(); + await btnCloseModal.click(); } loadModalNoFrame = async (loadShowModalPageWithFrame: boolean) => { @@ -248,4 +300,13 @@ export class Screen { await this.loadedModalFrame(); } + + loadSharedModal = async (loadShowModalPageWithFrame: boolean) => { + if (loadShowModalPageWithFrame) { + await this.showSharedModal(); + } + + const lbl = await this._driver.waitForElement(sharedModalView, 5000); + assert.isTrue(await lbl.isDisplayed()); + } } \ No newline at end of file diff --git a/e2e/modal-navigation-ng/e2e/shared.e2e-spec.ts b/e2e/modal-navigation-ng/e2e/screens/shared-screen.ts similarity index 82% rename from e2e/modal-navigation-ng/e2e/shared.e2e-spec.ts rename to e2e/modal-navigation-ng/e2e/screens/shared-screen.ts index 54e9f6a90..8b742de23 100644 --- a/e2e/modal-navigation-ng/e2e/shared.e2e-spec.ts +++ b/e2e/modal-navigation-ng/e2e/screens/shared-screen.ts @@ -1,10 +1,9 @@ import { AppiumDriver } from "nativescript-dev-appium"; import { Screen } from "./screen" +import { assert } from "chai"; const time = 1; - export const roots = ["setFrameRootView", "setLayoutRootView", "setTabRootView", "setNamedFrameRootView"]; -// export const roots = ["setTabRootView", "setNamedFrameRootView"]; export async function modalFrameBackground(driver: AppiumDriver, screen: Screen) { await driver.backgroundApp(time); @@ -85,3 +84,18 @@ export async function testSecondItemBackground(driver: AppiumDriver, screen: Scr await screen.navigateToFirstItem(); await screen.loadedFirstItem(); } + +export async function assertComponent(driver: AppiumDriver, message: string) { + const lbl = await driver.waitForElement(message, 5000); + assert.isTrue(await lbl.isDisplayed()); +} + +export async function navigateToSecondComponent(driver: AppiumDriver) { + const navigateBtnTap = await driver.findElementByAutomationText("Go To Second (to open shared modal)"); + await navigateBtnTap.click(); +} + +export async function goBack(driver: AppiumDriver) { + const backBtnTap = await driver.findElementByAutomationText("go back"); + await backBtnTap.click(); +} \ No newline at end of file diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-always-default.png b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-always-default.png new file mode 100644 index 000000000..81bf64f76 Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-always-default.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-always-hidden.png b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-always-hidden.png new file mode 100644 index 000000000..f0212faf3 Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-always-hidden.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-always-shown.png b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-always-shown.png new file mode 100644 index 000000000..f0212faf3 Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-always-shown.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-auto-default.png b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-auto-default.png new file mode 100644 index 000000000..283f26ca8 Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-auto-default.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-auto-hidden.png b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-auto-hidden.png new file mode 100644 index 000000000..6c433dfb5 Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-auto-hidden.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-auto-shown.png b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-auto-shown.png new file mode 100644 index 000000000..59ff9823b Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-auto-shown.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-never-default.png b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-never-default.png new file mode 100644 index 000000000..0b5d71b42 Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-never-default.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-never-hidden.png b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-never-hidden.png new file mode 100644 index 000000000..12af4ab42 Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-never-hidden.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-never-shown.png b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-never-shown.png new file mode 100644 index 000000000..12af4ab42 Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/actionBarVisibility-never-shown.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/tab-view-binding-second-tab.png b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/tab-view-binding-second-tab.png new file mode 100644 index 000000000..2a0c98ebf Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/tab-view-binding-second-tab.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/tab-view-binding-third-tab.png b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/tab-view-binding-third-tab.png new file mode 100644 index 000000000..ecd473fae Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone 7 12/tab-view-binding-third-tab.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-always-default.png b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-always-default.png new file mode 100644 index 000000000..6724bef38 Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-always-default.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-always-hidden.png b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-always-hidden.png new file mode 100644 index 000000000..61c63323c Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-always-hidden.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-always-shown.png b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-always-shown.png new file mode 100644 index 000000000..61c63323c Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-always-shown.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-auto-default.png b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-auto-default.png new file mode 100644 index 000000000..4482f1334 Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-auto-default.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-auto-hidden.png b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-auto-hidden.png new file mode 100644 index 000000000..48bca2281 Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-auto-hidden.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-auto-shown.png b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-auto-shown.png new file mode 100644 index 000000000..5c642f446 Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-auto-shown.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-never-default.png b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-never-default.png new file mode 100644 index 000000000..666767c49 Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-never-default.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-never-hidden.png b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-never-hidden.png new file mode 100644 index 000000000..2c44f8ccd Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-never-hidden.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-never-shown.png b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-never-shown.png new file mode 100644 index 000000000..2c44f8ccd Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/actionBarVisibility-never-shown.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/tab-view-binding-first-tab.png b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/tab-view-binding-first-tab.png new file mode 100644 index 000000000..e13752607 Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/tab-view-binding-first-tab.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/tab-view-binding-second-tab.png b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/tab-view-binding-second-tab.png new file mode 100644 index 000000000..1998b81c6 Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/tab-view-binding-second-tab.png differ diff --git a/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/tab-view-binding-third-tab.png b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/tab-view-binding-third-tab.png new file mode 100644 index 000000000..2297f4b97 Binary files /dev/null and b/e2e/renderer/e2e/resources/images/renderer/iPhone XR 12/tab-view-binding-third-tab.png differ diff --git a/nativescript-angular/directives/dialogs.ts b/nativescript-angular/directives/dialogs.ts index 7670320c5..899c54097 100644 --- a/nativescript-angular/directives/dialogs.ts +++ b/nativescript-angular/directives/dialogs.ts @@ -17,7 +17,7 @@ import { AppHostView } from "../app-host-view"; import { DetachedLoader } from "../common/detached-loader"; import { PageFactory, PAGE_FACTORY } from "../platform-providers"; import { once } from "../common/utils"; -import { Frame } from "tns-core-modules/ui/frame/frame"; +import { topmost, Frame } from "tns-core-modules/ui/frame"; export interface ModalDialogOptions { context?: any; @@ -84,7 +84,7 @@ export class ModalDialogService { let frame = parentView; if (!(parentView instanceof Frame)) { - frame = parentView.page && parentView.page.frame; + frame = (parentView.page && parentView.page.frame) || topmost(); } if (frame) { diff --git a/nativescript-angular/package.json b/nativescript-angular/package.json index 4e730b888..787e05755 100644 --- a/nativescript-angular/package.json +++ b/nativescript-angular/package.json @@ -1,6 +1,6 @@ { "name": "nativescript-angular", - "version": "7.0.0", + "version": "7.0.1", "description": "An Angular renderer that lets you build mobile apps with NativeScript.", "homepage": "https://www.nativescript.org/", "bugs": "https://github.com/NativeScript/nativescript-angular/issues", diff --git a/nativescript-angular/router/ns-location-strategy.ts b/nativescript-angular/router/ns-location-strategy.ts index 91135ece7..3798731b1 100644 --- a/nativescript-angular/router/ns-location-strategy.ts +++ b/nativescript-angular/router/ns-location-strategy.ts @@ -15,18 +15,30 @@ export class Outlet { // More than one key available when using NSEmptyOutletComponent component // in module that lazy loads children (loadChildren) and has outlet name. outletKeys: Array; + + // More than one frame available when using NSEmptyOutletComponent component + // in module that lazy loads children (loadChildren) and has outlet name. + frames: Array = []; + // The url path to the Outlet. + // E.G: the path to Outlet3 that is nested Outlet1(home)->Outlet2(nested1)->Outlet3(nested2) + // will be 'home/nested1' + path: string; pathByOutlets: string; states: Array = []; - frame: Frame; // Used in reuse-strategy by its children to determine if they should be detached too. shouldDetach: boolean = true; - constructor(outletKey: string, pathByOutlets: string, modalNavigationDepth?: number) { + constructor(outletKey: string, path: string, pathByOutlets: string, modalNavigationDepth?: number) { this.outletKeys = [outletKey]; this.isPageNavigationBack = false; this.showingModal = false; this.modalNavigationDepth = modalNavigationDepth || 0; this.pathByOutlets = pathByOutlets; + this.path = path; + } + + containsFrame(frame: Frame): boolean { + return this.frames.indexOf(frame) > -1; } peekState(): LocationState { @@ -88,7 +100,7 @@ export class NSLocationStrategy extends LocationStrategy { } let tree = this.currentUrlTree; - let changedOutlet = this.getSegmentGroup(this.currentOutlet.pathByOutlets); + let changedOutlet = this.getSegmentGroupByOutlet(this.currentOutlet); // Handle case where the user declares a component at path "/". // The url serializer doesn't parse this url as having a primary outlet. @@ -130,13 +142,13 @@ export class NSLocationStrategy extends LocationStrategy { // The url serializer doesn't parse this url as having a primary outlet. if (!Object.keys(urlTreeRoot.children).length) { const segmentGroup = this.currentUrlTree && this.currentUrlTree.root; - const outletKey = this.getSegmentGroupFullPath(segmentGroup) + "primary"; + const outletKey = this.getOutletKey(this.getSegmentGroupFullPath(segmentGroup), "primary"); const outlet = this.findOutletByKey(outletKey); if (outlet && this.updateStates(outlet, segmentGroup)) { this.currentOutlet = outlet; // If states updated } else if (!outlet) { - const rootOutlet = this.createOutlet("primary", segmentGroup, null); + const rootOutlet = this.createOutlet("primary", null, segmentGroup, null); this.currentOutlet = rootOutlet; } @@ -153,16 +165,19 @@ export class NSLocationStrategy extends LocationStrategy { currentSegmentGroup.outlet = outletName; currentSegmentGroup.root = urlTreeRoot; - let outletKey = this.getSegmentGroupFullPath(currentTree) + outletName; + const outletPath = this.getSegmentGroupFullPath(currentTree); + let outletKey = this.getOutletKey(outletPath, outletName); let outlet = this.findOutletByKey(outletKey); + const parentOutletName = currentTree.outlet || ""; - const parentOutletKey = this.getSegmentGroupFullPath(currentTree.parent) + parentOutletName; + const parentOutletPath = this.getSegmentGroupFullPath(currentTree.parent); + const parentOutletKey = this.getOutletKey(parentOutletPath, parentOutletName); const parentOutlet = this.findOutletByKey(parentOutletKey); const containsLastState = outlet && outlet.containsTopState(currentSegmentGroup.toString()); if (!outlet) { // tslint:disable-next-line:max-line-length - outlet = this.createOutlet(outletKey, currentSegmentGroup, parentOutlet, this._modalNavigationDepth); + outlet = this.createOutlet(outletKey, outletPath, currentSegmentGroup, parentOutlet, this._modalNavigationDepth); this.currentOutlet = outlet; } else if (this._modalNavigationDepth > 0 && outlet.showingModal && !containsLastState) { // Navigation inside modal view. @@ -235,7 +250,7 @@ export class NSLocationStrategy extends LocationStrategy { const topmostFrame = this.frameService.getFrame(); this.currentOutlet = this.getOutletByFrame(topmostFrame); } - this.currentOutlet.frame.goBack(); + this.currentOutlet.frames[this.currentOutlet.frames.length - 1].goBack(); } else { // Nested navigation - just pop the state if (isLogEnabled()) { @@ -270,7 +285,7 @@ export class NSLocationStrategy extends LocationStrategy { private callPopState(state: LocationState, pop: boolean = true, outlet?: Outlet) { outlet = outlet || this.currentOutlet; const urlSerializer = new DefaultUrlSerializer(); - let changedOutlet = this.getSegmentGroup(outlet.pathByOutlets); + let changedOutlet = this.getSegmentGroupByOutlet(outlet); if (state && changedOutlet) { this.updateSegmentGroup(this.currentUrlTree.root, changedOutlet, state.segmentGroup); @@ -344,20 +359,32 @@ export class NSLocationStrategy extends LocationStrategy { } this.currentOutlet = this.getOutletByFrame(frame); - this.currentOutlet.showingModal = true; - this._modalNavigationDepth++; + + // It is possible to have frame, but not corresponding Outlet, if + // showing modal dialog on app.component.ts ngOnInit() e.g. + if (this.currentOutlet) { + this.currentOutlet.showingModal = true; + this._modalNavigationDepth++; + } } public _closeModalNavigation() { if (isLogEnabled()) { routerLog("NSLocationStrategy.closeModalNavigation()"); } - this._modalNavigationDepth--; - this.currentOutlet = this.findOutletByModal(this._modalNavigationDepth, true) || this.currentOutlet; - this.currentOutlet.showingModal = false; + if (this._modalNavigationDepth > 0) { + this._modalNavigationDepth--; + } + + // currentOutlet should be the one that corresponds to the topmost() frame + const topmostOutlet = this.getOutletByFrame(this.frameService.getFrame()); + this.currentOutlet = this.findOutletByModal(this._modalNavigationDepth, true) || topmostOutlet; - this.callPopState(this.currentOutlet.peekState(), false); + if (this.currentOutlet) { + this.currentOutlet.showingModal = false; + this.callPopState(this.currentOutlet.peekState(), false); + } } public _beginPageNavigation(frame: Frame): NavigationOptions { @@ -402,20 +429,25 @@ export class NSLocationStrategy extends LocationStrategy { } updateOutletFrame(outlet: Outlet, frame: Frame) { - outlet.frame = frame; + if (!outlet.containsFrame(frame)) { + outlet.frames.push(frame); + } this.currentOutlet = outlet; } clearOutlet(frame: Frame) { this.outlets = this.outlets.filter(currentOutlet => { - // Remove current outlet, if it's named p-r-o, from the url tree. - const isEqualToCurrent = currentOutlet.pathByOutlets === this.currentOutlet.pathByOutlets; - const isModalOutlet = currentOutlet.modalNavigationDepth > 0; + let isEqualToCurrent; - if (currentOutlet.frame === frame && isModalOutlet && !isEqualToCurrent) { + if (this.currentOutlet) { + isEqualToCurrent = currentOutlet.pathByOutlets === this.currentOutlet.pathByOutlets; + } + + // Remove outlet from the url tree. + if (currentOutlet.containsFrame(frame) && !isEqualToCurrent) { this.callPopState(null, true, currentOutlet); } - return currentOutlet.frame !== frame; + return !currentOutlet.containsFrame(frame); }); } @@ -454,7 +486,7 @@ export class NSLocationStrategy extends LocationStrategy { currentRoute = currentRoute.parent; } - return fullPath ? fullPath + outletName : outletName; + return fullPath ? fullPath + "-" + outletName : outletName; } @@ -504,7 +536,7 @@ export class NSLocationStrategy extends LocationStrategy { for (let index = 0; index < this.outlets.length; index++) { const currentOutlet = this.outlets[index]; - if (currentOutlet.frame === frame) { + if (currentOutlet.containsFrame(frame)) { outlet = currentOutlet; break; } @@ -553,9 +585,10 @@ export class NSLocationStrategy extends LocationStrategy { } } - private createOutlet(outletKey: string, segmentGroup: any, parent: Outlet, modalNavigation?: number): Outlet { + // tslint:disable-next-line:max-line-length + private createOutlet(outletKey: string, path: string, segmentGroup: any, parent: Outlet, modalNavigation?: number): Outlet { const pathByOutlets = this.getPathByOutlets(segmentGroup); - const newOutlet = new Outlet(outletKey, pathByOutlets, modalNavigation); + const newOutlet = new Outlet(outletKey, path, pathByOutlets, modalNavigation); const locationState: LocationState = { segmentGroup: segmentGroup, @@ -575,15 +608,18 @@ export class NSLocationStrategy extends LocationStrategy { return newOutlet; } - private getSegmentGroup(pathByOutlets: string): UrlSegmentGroup { - const pathList = pathByOutlets.split("-"); + private getSegmentGroupByOutlet(outlet: Outlet): UrlSegmentGroup { + const pathList = outlet.pathByOutlets.split("-"); let segmentGroup = this.currentUrlTree.root; + let pathToOutlet; for (let index = 0; index < pathList.length; index++) { const currentPath = pathList[index]; const childrenCount = Object.keys(segmentGroup.children).length; if (childrenCount && segmentGroup.children[currentPath]) { + const url = segmentGroup.toString(); + pathToOutlet = pathToOutlet ? pathToOutlet + "/" + url : url; segmentGroup = segmentGroup.children[currentPath]; } else { // If no child outlet found with the given name - forget about all previously found outlets. @@ -594,6 +630,12 @@ export class NSLocationStrategy extends LocationStrategy { } } + // Paths should also match since there could be another Outlet + // with the same pathByOutlets but different url path. + if (segmentGroup && outlet.path && pathToOutlet && outlet.path !== pathToOutlet) { + segmentGroup = null; + } + return segmentGroup; } @@ -630,11 +672,17 @@ export class NSLocationStrategy extends LocationStrategy { // No currentModalOutlet available when opening 'primary' p-r-o. const outletName = "primary"; - const outletKey = parentOutlet.peekState().segmentGroup.toString() + outletName; - currentModalOutlet = this.createOutlet(outletKey, segmentedGroup, parentOutlet, this._modalNavigationDepth); + const outletPath = parentOutlet.peekState().segmentGroup.toString(); + const outletKey = this.getOutletKey(outletPath, outletName); + // tslint:disable-next-line:max-line-length + currentModalOutlet = this.createOutlet(outletKey, outletPath, segmentedGroup, parentOutlet, this._modalNavigationDepth); this.currentOutlet = currentModalOutlet; } else if (this.updateStates(currentModalOutlet, segmentedGroup)) { this.currentOutlet = currentModalOutlet; // If states updated } } + + private getOutletKey(path: string, outletName: string): string { + return path ? path + "-" + outletName : outletName; + } } diff --git a/nativescript-angular/router/page-router-outlet.ts b/nativescript-angular/router/page-router-outlet.ts index bb2d18c6a..593a2c2af 100644 --- a/nativescript-angular/router/page-router-outlet.ts +++ b/nativescript-angular/router/page-router-outlet.ts @@ -391,7 +391,7 @@ export class PageRouterOutlet implements OnDestroy { // tslint:disable-line:dire let outletKeyForRoute = this.locationStrategy.getRouteFullPath(nodeToMark); let outlet = this.locationStrategy.findOutletByKey(outletKeyForRoute); - if (outlet && outlet.frame) { + if (outlet && outlet.frames.length) { nodeToMark[pageRouterActivatedSymbol] = true; if (isLogEnabled()) { log("Activated route marked as page: " + routeToString(nodeToMark)); diff --git a/tests/app/tests/modal-dialog.ts b/tests/app/tests/modal-dialog.ts index babe84507..8c6fb9760 100644 --- a/tests/app/tests/modal-dialog.ts +++ b/tests/app/tests/modal-dialog.ts @@ -93,11 +93,11 @@ describe("modal-dialog", () => { .then((fixture: ComponentFixture) => { const service = fixture.componentRef.instance.service; const locStrategy = fixture.componentRef.instance.locationStrategy; - const outlet = new Outlet("primary", "primary", 0); + const outlet = new Outlet("primary", null, "primary", 0); let parentView = fixture.componentRef.instance.vcRef.element.nativeElement; parentView = parentView.page && parentView.page.frame; - outlet.frame = parentView; + outlet.frames.push(parentView); locStrategy._getOutlets().push(outlet); locStrategy.pushState(null, "test", "/test", null); @@ -115,11 +115,11 @@ describe("modal-dialog", () => { .then((fixture: ComponentFixture) => { const service = fixture.componentRef.instance.service; const locStrategy = fixture.componentRef.instance.locationStrategy; - const outlet = new Outlet("primary", "primary", 0); + const outlet = new Outlet("primary", null, "primary", 0); let parentView = fixture.componentRef.instance.vcRef.element.nativeElement; parentView = parentView.page && parentView.page.frame; - outlet.frame = parentView; + outlet.frames.push(parentView); locStrategy._getOutlets().push(outlet); locStrategy.pushState(null, "test", "/test", null); diff --git a/tests/app/tests/ns-location-strategy.ts b/tests/app/tests/ns-location-strategy.ts index c42f180cf..2f7208903 100644 --- a/tests/app/tests/ns-location-strategy.ts +++ b/tests/app/tests/ns-location-strategy.ts @@ -143,7 +143,7 @@ function simulatePageNavigation(strategy: NSLocationStrategy, url: string, frame strategy.pushState(null, null, url, null); const outlet: Outlet = strategy.findOutletByOutletPath(outletName); - outlet.frame = frame; + outlet.frames.push(frame); strategy._beginPageNavigation(frame); }