| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1,13 +1,12 @@ | |||
| 1 | - import * as helper from "../helper"; | ||
| 2 | 1 | import TKUnit = require("../../TKUnit"); | |
| 3 | - import { isIOS, isAndroid } from "tns-core-modules/platform"; | ||
| 2 | + import { isAndroid } from "tns-core-modules/platform"; | ||
| 4 | 3 | import { _resetRootView } from "tns-core-modules/application/"; | |
| 5 | 4 | import { Frame, NavigationEntry, topmost } from "tns-core-modules/ui/frame"; | |
| 6 | 5 | import { Page } from "tns-core-modules/ui/page"; | |
| 7 | 6 | import { TabView, TabViewItem } from "tns-core-modules/ui/tab-view"; | |
| 8 | 7 | ||
| 9 | 8 | function waitUntilNavigatedToMaxTimeout(pages: Page[], action: Function) { | |
| 10 | - const maxTimeout = 5; | ||
| 9 | + const maxTimeout = 8; | ||
| 11 | 10 | let completed = 0; | |
| 12 | 11 | function navigatedTo(args) { | |
| 13 | 12 | args.object.page.off("navigatedTo", navigatedTo); | |
@@ -67,13 +66,19 @@ export function test_frame_topmost_matches_selectedIndex() { | |||
| 67 | 66 | create: () => tabView | |
| 68 | 67 | }; | |
| 69 | 68 | ||
| 70 | - waitUntilNavigatedToMaxTimeout([items[0].page], () => _resetRootView(entry)); | ||
| 71 | - | ||
| 72 | - TKUnit.assertEqual(topmost().id, "Tab0 Frame0"); | ||
| 73 | - | ||
| 74 | - waitUntilNavigatedToMaxTimeout([items[1].page], () => tabView.selectedIndex = 1); | ||
| 75 | - | ||
| 76 | - TKUnit.assertEqual(topmost().id, "Tab1 Frame1"); | ||
| 69 | + if (isAndroid) { | ||
| 70 | + waitUntilNavigatedToMaxTimeout([items[0].page, items[1].page], () => _resetRootView(entry)); | ||
| 71 | + TKUnit.assertEqual(topmost().id, "Tab0 Frame0"); | ||
| 72 | + | ||
| 73 | + tabView.selectedIndex = 1; | ||
| 74 | + TKUnit.assertEqual(topmost().id, "Tab1 Frame1"); | ||
| 75 | + } else { | ||
| 76 | + waitUntilNavigatedToMaxTimeout([items[0].page], () => _resetRootView(entry)); | ||
| 77 | + TKUnit.assertEqual(topmost().id, "Tab0 Frame0"); | ||
| 78 | + | ||
| 79 | + waitUntilNavigatedToMaxTimeout([items[1].page], () => tabView.selectedIndex = 1); | ||
| 80 | + TKUnit.assertEqual(topmost().id, "Tab1 Frame1"); | ||
| 81 | + } | ||
| 77 | 82 | } | |
| 78 | 83 | ||
| 79 | 84 | export function test_offset_zero_should_raise_same_events() { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -234,6 +234,7 @@ export class View extends ViewCommon { | |||
| 234 | 234 | private layoutChangeListenerIsSet: boolean; | |
| 235 | 235 | private layoutChangeListener: android.view.View.OnLayoutChangeListener; | |
| 236 | 236 | private _manager: android.support.v4.app.FragmentManager; | |
| 237 | + private _rootManager: android.support.v4.app.FragmentManager; | ||
| 237 | 238 | ||
| 238 | 239 | nativeViewProtected: android.view.View; | |
| 239 | 240 | ||
@@ -265,20 +266,52 @@ export class View extends ViewCommon { | |||
| 265 | 266 | } | |
| 266 | 267 | } | |
| 267 | 268 | ||
| 269 | + public _getChildFragmentManager(): android.support.v4.app.FragmentManager { | ||
| 270 | + return null; | ||
| 271 | + } | ||
| 272 | + | ||
| 273 | + public _getRootFragmentManager(): android.support.v4.app.FragmentManager { | ||
| 274 | + if (!this._rootManager && this._context) { | ||
| 275 | + this._rootManager = (<android.support.v4.app.FragmentActivity>this._context).getSupportFragmentManager(); | ||
| 276 | + } | ||
| 277 | + | ||
| 278 | + return this._rootManager; | ||
| 279 | + } | ||
| 280 | + | ||
| 268 | 281 | public _getFragmentManager(): android.support.v4.app.FragmentManager { | |
| 269 | 282 | let manager = this._manager; | |
| 270 | 283 | if (!manager) { | |
| 271 | 284 | let view: View = this; | |
| 285 | + let frameOrTabViewItemFound = false; | ||
| 272 | 286 | while (view) { | |
| 287 | + // when interacting with nested fragments instead of using getSupportFragmentManager | ||
| 288 | + // we must always use getChildFragmentManager instead; | ||
| 289 | + // we have three sources of fragments -- Frame fragments, TabViewItem fragments, and | ||
| 290 | + // modal dialog fragments | ||
| 291 | + | ||
| 292 | + // modal -> frame / tabview (frame / tabview use modal CHILD fm) | ||
| 273 | 293 | const dialogFragment = view._dialogFragment; | |
| 274 | 294 | if (dialogFragment) { | |
| 275 | 295 | manager = dialogFragment.getChildFragmentManager(); | |
| 276 | 296 | break; | |
| 277 | - } else { | ||
| 278 | - // the case is needed because _dialogFragment is on View | ||
| 279 | - // but parent may be ViewBase. | ||
| 280 | - view = view.parent as View; | ||
| 281 | 297 | } | |
| 298 | + | ||
| 299 | + // - frame1 -> frame2 (frame2 uses frame1 CHILD fm) | ||
| 300 | + // - tabview -> frame1 (frame1 uses tabview item CHILD fm) | ||
| 301 | + // - frame1 -> tabview (tabview uses frame1 CHILD fm) | ||
| 302 | + // - frame1 -> tabview -> frame2 (tabview uses frame1 CHILD fm; frame2 uses tabview item CHILD fm) | ||
| 303 | + if (view._hasFragments) { | ||
| 304 | + if (frameOrTabViewItemFound) { | ||
| 305 | + manager = view._getChildFragmentManager(); | ||
| 306 | + break; | ||
| 307 | + } | ||
| 308 | + | ||
| 309 | + frameOrTabViewItemFound = true; | ||
| 310 | + } | ||
| 311 | + | ||
| 312 | + // the case is needed because _dialogFragment is on View | ||
| 313 | + // but parent may be ViewBase. | ||
| 314 | + view = view.parent as View; | ||
| 282 | 315 | } | |
| 283 | 316 | ||
| 284 | 317 | if (!manager && this._context) { | |
@@ -294,6 +327,7 @@ export class View extends ViewCommon { | |||
| 294 | 327 | @profile | |
| 295 | 328 | public onLoaded() { | |
| 296 | 329 | this._manager = null; | |
| 330 | + this._rootManager = null; | ||
| 297 | 331 | super.onLoaded(); | |
| 298 | 332 | this.setOnTouchListener(); | |
| 299 | 333 | } | |
@@ -307,6 +341,7 @@ export class View extends ViewCommon { | |||
| 307 | 341 | } | |
| 308 | 342 | ||
| 309 | 343 | this._manager = null; | |
| 344 | + this._rootManager = null; | ||
| 310 | 345 | super.onUnloaded(); | |
| 311 | 346 | } | |
| 312 | 347 | ||
@@ -405,6 +440,10 @@ export class View extends ViewCommon { | |||
| 405 | 440 | return false; | |
| 406 | 441 | } | |
| 407 | 442 | ||
| 443 | + get _hasFragments(): boolean { | ||
| 444 | + return false; | ||
| 445 | + } | ||
| 446 | + | ||
| 408 | 447 | public layoutNativeView(left: number, top: number, right: number, bottom: number): void { | |
| 409 | 448 | if (this.nativeViewProtected) { | |
| 410 | 449 | this.nativeViewProtected.layout(left, top, right, bottom); | |
@@ -571,7 +610,7 @@ export class View extends ViewCommon { | |||
| 571 | 610 | this._dialogFragment = df; | |
| 572 | 611 | this._raiseShowingModallyEvent(); | |
| 573 | 612 | ||
| 574 | - this._dialogFragment.show(parent._getFragmentManager(), this._domId.toString()); | ||
| 613 | + this._dialogFragment.show(parent._getRootFragmentManager(), this._domId.toString()); | ||
| 575 | 614 | } | |
| 576 | 615 | ||
| 577 | 616 | protected _hideNativeModalView(parent: View) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -121,6 +121,10 @@ export class Frame extends FrameBase { | |||
| 121 | 121 | return this._android; | |
| 122 | 122 | } | |
| 123 | 123 | ||
| 124 | + get _hasFragments(): boolean { | ||
| 125 | + return true; | ||
| 126 | + } | ||
| 127 | + | ||
| 124 | 128 | _onAttachedToWindow(): void { | |
| 125 | 129 | super._onAttachedToWindow(); | |
| 126 | 130 | this._attachedToWindow = true; | |
@@ -175,7 +179,16 @@ export class Frame extends FrameBase { | |||
| 175 | 179 | } | |
| 176 | 180 | } | |
| 177 | 181 | ||
| 178 | - _onRootViewReset(): void { | ||
| 182 | + public _getChildFragmentManager() { | ||
| 183 | + const backstackEntry = this._executingEntry || this._currentEntry; | ||
| 184 | + if (backstackEntry && backstackEntry.fragment && backstackEntry.fragment.isAdded()) { | ||
| 185 | + return backstackEntry.fragment.getChildFragmentManager(); | ||
| 186 | + } | ||
| 187 | + | ||
| 188 | + return null; | ||
| 189 | + } | ||
| 190 | + | ||
| 191 | + public _onRootViewReset(): void { | ||
| 179 | 192 | this.disposeCurrentFragment(); | |
| 180 | 193 | super._onRootViewReset(); | |
| 181 | 194 | } | |
@@ -186,7 +199,14 @@ export class Frame extends FrameBase { | |||
| 186 | 199 | } | |
| 187 | 200 | ||
| 188 | 201 | private disposeCurrentFragment(): void { | |
| 189 | - if (!this._currentEntry || !this._currentEntry.fragment) { | ||
| 202 | + // when interacting with nested fragments it seems Android is smart enough | ||
| 203 | + // to automatically remove child fragments when parent fragment is removed; | ||
| 204 | + // however, we must add a fragment.isAdded() guard as our logic will try to | ||
| 205 | + // explicitly remove the already removed child fragment causing an | ||
| 206 | + // IllegalStateException: Fragment has not been attached yet. | ||
| 207 | + if (!this._currentEntry || | ||
| 208 | + !this._currentEntry.fragment || | ||
| 209 | + !this._currentEntry.fragment.isAdded()) { | ||
| 190 | 210 | return; | |
| 191 | 211 | } | |
| 192 | 212 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -125,6 +125,10 @@ export class Frame extends View { | |||
| 125 | 125 | * @private | |
| 126 | 126 | */ | |
| 127 | 127 | _currentEntry: BackstackEntry; | |
| 128 | + /** | ||
| 129 | + * @private | ||
| 130 | + */ | ||
| 131 | + _executingEntry: BackstackEntry; | ||
| 128 | 132 | /** | |
| 129 | 133 | * @private | |
| 130 | 134 | */ | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -260,6 +260,10 @@ export class TabViewItem extends TabViewItemBase { | |||
| 260 | 260 | public index: number; | |
| 261 | 261 | private _defaultTransformationMethod: android.text.method.TransformationMethod; | |
| 262 | 262 | ||
| 263 | + get _hasFragments(): boolean { | ||
| 264 | + return true; | ||
| 265 | + } | ||
| 266 | + | ||
| 263 | 267 | public initNativeView(): void { | |
| 264 | 268 | super.initNativeView(); | |
| 265 | 269 | if (this.nativeViewProtected) { | |
@@ -297,6 +301,24 @@ export class TabViewItem extends TabViewItemBase { | |||
| 297 | 301 | } | |
| 298 | 302 | } | |
| 299 | 303 | ||
| 304 | + public _getChildFragmentManager(): android.support.v4.app.FragmentManager { | ||
| 305 | + const tabView = this.parent as TabView; | ||
| 306 | + let tabFragment = null; | ||
| 307 | + const fragmentManager = tabView._getFragmentManager(); | ||
| 308 | + for (let fragment of (<Array<any>>fragmentManager.getFragments().toArray())) { | ||
| 309 | + if (fragment.index === this.index) { | ||
| 310 | + tabFragment = fragment; | ||
| 311 | + break; | ||
| 312 | + } | ||
| 313 | + } | ||
| 314 | + | ||
| 315 | + if (!tabFragment) { | ||
| 316 | + throw new Error(`Could not get child fragment manager for tab item with index ${this.index}`); | ||
| 317 | + } | ||
| 318 | + | ||
| 319 | + return tabFragment.getChildFragmentManager(); | ||
| 320 | + } | ||
| 321 | + | ||
| 300 | 322 | [fontSizeProperty.getDefault](): { nativeSize: number } { | |
| 301 | 323 | return { nativeSize: this.nativeViewProtected.getTextSize() }; | |
| 302 | 324 | } | |
@@ -361,6 +383,10 @@ export class TabView extends TabViewBase { | |||
| 361 | 383 | tabs.push(new WeakRef(this)); | |
| 362 | 384 | } | |
| 363 | 385 | ||
| 386 | + get _hasFragments(): boolean { | ||
| 387 | + return true; | ||
| 388 | + } | ||
| 389 | + | ||
| 364 | 390 | public onItemsChanged(oldItems: TabViewItem[], newItems: TabViewItem[]): void { | |
| 365 | 391 | super.onItemsChanged(oldItems, newItems); | |
| 366 | 392 | ||
@@ -512,6 +538,20 @@ export class TabView extends TabViewBase { | |||
| 512 | 538 | return false; | |
| 513 | 539 | } | |
| 514 | 540 | ||
| 541 | + public _onRootViewReset(): void { | ||
| 542 | + this.disposeCurrentFragments(); | ||
| 543 | + super._onRootViewReset(); | ||
| 544 | + } | ||
| 545 | + | ||
| 546 | + private disposeCurrentFragments(): void { | ||
| 547 | + const fragmentManager = this._getFragmentManager(); | ||
| 548 | + const transaction = fragmentManager.beginTransaction(); | ||
| 549 | + for (let fragment of (<Array<any>>fragmentManager.getFragments().toArray())) { | ||
| 550 | + transaction.remove(fragment); | ||
| 551 | + } | ||
| 552 | + transaction.commitNowAllowingStateLoss(); | ||
| 553 | + } | ||
| 554 | + | ||
| 515 | 555 | private shouldUpdateAdapter(items: Array<TabViewItemDefinition>) { | |
| 516 | 556 | if (!this._pagerAdapter) { | |
| 517 | 557 | return false; | |
| Back | FazBrowse Home | New Git URL |
0 commit comments