Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Loading builder for Route #3113

Merged
merged 15 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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();
}
}
Loading