Visitar URL original
[add] updating nested Beamers on parent navigation · austinstoker/packages@5ef19c7 · GitHub
Skip to content

Commit 5ef19c7

Browse files
committed
[add] updating nested Beamers on parent navigation
- can be disabled via BeamerDelegate.updateFromParent boolean - closes flutter#291
1 parent d75d36e commit 5ef19c7

2 files changed

Lines changed: 108 additions & 1 deletion

File tree

‎package/lib/src/beamer_delegate.dart‎

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ class BeamerDelegate<T extends BeamState> extends RouterDelegate<BeamState>
2828
this.beamBackTransitionDelegate = const ReverseTransitionDelegate(),
2929
this.onPopPage,
3030
this.setBrowserTabTitle = true,
31+
this.updateFromParent = true,
3132
}) {
3233
notFoundPage ??= BeamPage(
3334
title: 'Not found',
@@ -64,6 +65,9 @@ class BeamerDelegate<T extends BeamState> extends RouterDelegate<BeamState>
6465
set parent(BeamerDelegate? parent) {
6566
_parent = parent!;
6667
_initializeFromParent();
68+
if (updateFromParent) {
69+
_parent!.addListener(_updateFromParent);
70+
}
6771
}
6872

6973
/// The top-most [BeamerDelegate], a parent of all.
@@ -193,6 +197,11 @@ class BeamerDelegate<T extends BeamState> extends RouterDelegate<BeamState>
193197
/// be used to set and update the browser tab title.
194198
final bool setBrowserTabTitle;
195199

200+
/// Whether to call [update] when parent notifies listeners.
201+
///
202+
/// This means that navigation can be done either on parent or on this
203+
final bool updateFromParent;
204+
196205
final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>();
197206

198207
/// The history of beaming states.
@@ -300,6 +309,7 @@ class BeamerDelegate<T extends BeamState> extends RouterDelegate<BeamState>
300309
bool replaceCurrent = false,
301310
bool buildBeamLocation = true,
302311
bool rebuild = true,
312+
bool updateParent = true,
303313
}) {
304314
active = true;
305315
_popState = popState ?? _popState;
@@ -317,7 +327,7 @@ class BeamerDelegate<T extends BeamState> extends RouterDelegate<BeamState>
317327
listener?.call(this.state, _currentBeamLocation);
318328
}
319329

320-
if (state != _parent?.state) {
330+
if (state != _parent?.state && updateParent) {
321331
_parent?.update(
322332
state: this.state.copyWith(),
323333
rebuild: false,
@@ -724,6 +734,14 @@ class BeamerDelegate<T extends BeamState> extends RouterDelegate<BeamState>
724734
_pushHistory(location);
725735
}
726736

737+
void _updateFromParent({bool rebuild = true}) {
738+
update(
739+
state: createState!(_parent!.state),
740+
rebuild: rebuild,
741+
updateParent: false,
742+
);
743+
}
744+
727745
void _updateFromLocation({bool rebuild = true}) {
728746
update(
729747
state: createState!(_currentBeamLocation.state),
@@ -734,6 +752,7 @@ class BeamerDelegate<T extends BeamState> extends RouterDelegate<BeamState>
734752

735753
@override
736754
void dispose() {
755+
_parent?.removeListener(_updateFromParent);
737756
_currentBeamLocation.removeListener(_updateFromLocation);
738757
super.dispose();
739758
}

‎package/test/beamer_delegate_test.dart‎

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,4 +362,92 @@ void main() {
362362
expect(delegate.currentBeamLocation.state.data, {});
363363
});
364364
});
365+
366+
group('Updating from parent', () {
367+
testWidgets('navigation on parent updates nested Beamer', (tester) async {
368+
final childDelegate = BeamerDelegate(
369+
locationBuilder: SimpleLocationBuilder(
370+
routes: {
371+
'/': (context) => Container(),
372+
'/test': (context) => Container(),
373+
'/test2': (context) => Container(),
374+
},
375+
),
376+
);
377+
final rootDelegate = BeamerDelegate(
378+
locationBuilder: SimpleLocationBuilder(
379+
routes: {
380+
'*': (context) => BeamPage(
381+
key: ValueKey('always-the-same'),
382+
child: Beamer(
383+
routerDelegate: childDelegate,
384+
),
385+
),
386+
},
387+
),
388+
);
389+
await tester.pumpWidget(
390+
MaterialApp.router(
391+
routeInformationParser: BeamerParser(),
392+
routerDelegate: rootDelegate,
393+
),
394+
);
395+
396+
rootDelegate.beamToNamed('/test');
397+
await tester.pump();
398+
expect(rootDelegate.state.uri.toString(), '/test');
399+
expect(childDelegate.state.uri.toString(), '/test');
400+
expect(childDelegate.beamStateHistory.length, 1);
401+
402+
rootDelegate.beamToNamed('/test2');
403+
await tester.pump();
404+
expect(rootDelegate.state.uri.toString(), '/test2');
405+
expect(childDelegate.state.uri.toString(), '/test2');
406+
expect(childDelegate.beamStateHistory.length, 2);
407+
});
408+
409+
testWidgets("navigation on parent doesn't update nested Beamer",
410+
(tester) async {
411+
final childDelegate = BeamerDelegate(
412+
updateFromParent: false,
413+
locationBuilder: SimpleLocationBuilder(
414+
routes: {
415+
'/': (context) => Container(),
416+
'/test': (context) => Container(),
417+
'/test2': (context) => Container(),
418+
},
419+
),
420+
);
421+
final rootDelegate = BeamerDelegate(
422+
locationBuilder: SimpleLocationBuilder(
423+
routes: {
424+
'*': (context) => BeamPage(
425+
key: ValueKey('always-the-same'),
426+
child: Beamer(
427+
routerDelegate: childDelegate,
428+
),
429+
),
430+
},
431+
),
432+
);
433+
await tester.pumpWidget(
434+
MaterialApp.router(
435+
routeInformationParser: BeamerParser(),
436+
routerDelegate: rootDelegate,
437+
),
438+
);
439+
440+
rootDelegate.beamToNamed('/test'); // initial will update
441+
await tester.pump();
442+
expect(rootDelegate.state.uri.toString(), '/test');
443+
expect(childDelegate.state.uri.toString(), '/test');
444+
expect(childDelegate.beamStateHistory.length, 1);
445+
446+
rootDelegate.beamToNamed('/test2');
447+
await tester.pump();
448+
expect(rootDelegate.state.uri.toString(), '/test2');
449+
expect(childDelegate.state.uri.toString(), '/test');
450+
expect(childDelegate.beamStateHistory.length, 1);
451+
});
452+
});
365453
}

0 commit comments

Comments
 (0)