Skip to content

Commit

Permalink
feat: Loading builder for Route (#3113)
Browse files Browse the repository at this point in the history
This change is mainly to make it easier for specifying loading screen
along when routing between component using the ``RouterComponent``.
Currently the change is only made on ``Route``, that now have optional
``loadingBuilder`` to Route constructor which would expect a
``Component``, which would be added as the loading page/screen while
``onLoad`` of the ``builder`` (the main routing component) to be
completed.

---------

Co-authored-by: Lukas Klingsbo <[email protected]>
  • Loading branch information
PistonShot1 and spydon authored Jul 24, 2024
1 parent e9512e9 commit 1e62b34
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 2 deletions.
25 changes: 23 additions & 2 deletions packages/flame/lib/src/components/route.dart
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ class Route extends PositionComponent
with ParentIsA<RouterComponent>, HasTimeScale {
Route(
Component Function()? builder, {
Component Function()? loadingBuilder,
this.transparent = false,
this.maintainState = true,
}) : _builder = builder,
_loadingBuilder = loadingBuilder,
_renderEffect = Decorator();

/// If true, then the route below this one will continue to be rendered when
Expand All @@ -53,6 +55,10 @@ class Route extends PositionComponent
/// in which case the user must override the [build] method.
final Component Function()? _builder;

/// The function that will build the loading page component, which is shown
/// when this route first becomes active, but hasn't fully loaded yet.
final Component Function()? _loadingBuilder;

/// This method is invoked when the route is pushed on top of the
/// [RouterComponent]'s stack.
///
Expand Down Expand Up @@ -118,17 +124,32 @@ class Route extends PositionComponent
/// also be added as a child component.
Component? _page;

/// The loadingPage that was built and is now owned by this route. The
/// [_loadingPage] will also be added as a child component.
Component? _loadingPage;

/// Additional visual effect that may be applied to the page during rendering.
final Decorator _renderEffect;

/// Invoked by the [RouterComponent] when this route is pushed to the top
/// of the navigation stack.
/// of the navigation stack
@internal
void didPush(Route? previousRoute) {
_page ??= build()..addToParent(this);
_page ??= build();
(_loadingBuilder != null) ? _addLoadingPage() : _page!.addToParent(this);
onPush(previousRoute);
}

/// Adds the [_loadingPage] to the parent and invoked by [didPush] , when
/// [_loadingBuilder] is specified
Future<void> _addLoadingPage() async {
_loadingPage ??= _loadingBuilder!()..addToParent(this);
await _loadingPage!.loaded;
await add(_page!);
await _page!.loaded;
_loadingPage!.removeFromParent();
}

/// Invoked by the [RouterComponent] when this route is popped off the top
/// of the navigation stack.
/// If [maintainState] is false, the page component rendered by this route
Expand Down
48 changes: 48 additions & 0 deletions packages/flame/test/components/route_test.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:ui';

import 'package:flame/components.dart';
Expand Down Expand Up @@ -474,6 +475,43 @@ void main() {
);
},
);
testWithFlameGame('Route with loading', (game) async {
final loadingComponent = PositionComponent(size: Vector2.all(100));
final pageComponent = _HeavyComponent()..size = Vector2.all(100);
final router = RouterComponent(
initialRoute: 'new',
routes: {
'start': Route(
Component.new,
),
'new': Route(
() {
return pageComponent;
},
loadingBuilder: () {
return loadingComponent;
},
),
},
);
game.add(router);
await game.ready();
expect(
pageComponent.isMounted,
isFalse,
);
expect(loadingComponent.isMounted, isTrue);
pageComponent.completer.complete();
await game.ready();
expect(
pageComponent.isMounted,
isTrue,
);
expect(
loadingComponent.isRemoved,
isTrue,
);
});
});
}

Expand Down Expand Up @@ -527,3 +565,13 @@ class _ColoredComponent extends PositionComponent {
canvas.drawRect(size.toRect(), _paint);
}
}

class _HeavyComponent extends PositionComponent {
Duration dummyTime = const Duration(seconds: 3);
Completer<void> completer = Completer();
@override
FutureOr<void> onLoad() async {
await completer.future;
return super.onLoad();
}
}

0 comments on commit 1e62b34

Please sign in to comment.