Closed KirioXX closed 2 years ago
@KirioXX how are you navigating? show me some code. also is there a reason you're nesting what seems to be main routes?
@Milad-Akarie thanks for the quick response. I have changed my setup a bit I removed the splash screen and let the MainPage wrapper deal with the navigation. Our application is pretty strict with where you can be at which state (handled by bloc). That's why I wanted to wrap our main routes to have a central point for the needed bloc providers and for the navigation.
For more context the main page looks a bit like this:
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:app/application/setup/setup_cubit.dart';
import 'package:app/application/state/state_cubit.dart';
import 'package:app/application/station/station_cubit.dart';
import 'package:app/presentation/routes/router.gr.dart';
class MainPage extends StatelessWidget {
const MainPage({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MultiBlocListener(
listeners: [
BlocListener<SetupCubit, SetupState>(
listener: (context, state) async {
if (state.setup == null) {
await _stateRouting(context, )
} else {
await context.router.pushAndPopUntil(
const SetupRoute(),
predicate: (_) => false,
);
}
}),
BlocListener<StateCubit, StateState>(
listener: _stateRouting,
)
],
child: const AutoRouter(),
);
}
Future<void> _stateRouting(BuildContext context, StateState stateState) async {
final page = stateState.maybeMap(
stateOne: (_) => const StateOneRoute(),
stateTwo: (_) => const StateTwoRoute(),
stateThree: (_) => const StateThreeRoute() ,
loading: (_) => null,
orElse: () => const SetupRoute(),
);
if (page != null && context.routeData.isActive) {
await context.router.pushAndPopUntil(
page,
predicate: (route) => false,
);
}
}
}
and this is the updated config:
import 'package:auto_route/auto_route.dart';
import 'package:app/presentation/pages/job/job_preflight_page.dart';
import 'package:app/presentation/pages/main_page.dart';
import 'package:app/presentation/routes/auth_guard.dart';
import 'package:app_auth/auth.dart';
import 'package:app/presentation/pages/station/station_pick_page.dart';
import 'package:app/presentation/pages/work_order/work_order_scann_in_page.dart';
import 'package:app/presentation/pages/job/job_in_progress_page/job_in_progress_page.dart';
import 'package:app/presentation/pages/job/job_break_page.dart';
import 'package:app/presentation/pages/job/job_clocked_out_page.dart';
import 'package:app/presentation/pages/job/job_finished_page.dart';
import 'package:app/presentation/pages/job/job_overrun_form_page.dart';
import 'package:app/presentation/pages/job/job_overrun_submit_page.dart';
import 'package:app/presentation/pages/barcode_scanner/barcode_scanner_page.dart';
@MaterialAutoRouter(
replaceInRouteName: 'Page|Dialog,Route',
routes: <AutoRoute>[
AutoRoute(
page: MainPage,
initial: true,
guards: [AuthGuard],
children: [
AutoRoute(page: StationsPickPage),
AutoRoute(page: WorkOrderScannInPage),
AutoRoute(page: JobPreflightPage),
AutoRoute(page: JobInProgressPage),
AutoRoute(page: JobBreakPage),
AutoRoute(page: JobClockedOutPage),
AutoRoute(page: JobFinishedPage),
AutoRoute(page: JobOverrunFormPage),
AutoRoute(page: JobOverrunSubmitPage),
AutoRoute(page: BarCodeScannerPage),
],
),
// Auth
AutoRoute(page: LoginPage),
],
)
class $AppRouter {}
This works fine for most cases but fails for some when the MainPage gets rebuilt unexpected.
this looks like a good use-case for a declarative router, do any of your state-routes have nested children?
anyways, with your setup you're referencing the root router, which automatically tries to find the child router that can handle the nested routes you're pushing, I'm still not sure why your MainPage would rebuild but there are a few things we could try.
you could make AutoRouter widget the root widget inside of MainPage.
@override
Widget build(BuildContext context) {
return AutoRouter(
builder: (context,routerWidget){
return MultiBlocListener(
listeners: [
BlocListener<SetupCubit, SetupState>(
listener: (context, state) async {
if (state.setup == null) {
await _stateRouting(context, )
} else {
// now context.router will obtain the nested router not the root router
await context.router.pushAndPopUntil(
const SetupRoute(),
predicate: (_) => false,
);
}
}),
BlocListener<StateCubit, StateState>(
listener: _stateRouting,
)
],
child: routerWidget,
);
}
)
}
you can also try declarative routing.
@override
Widget build(BuildContext context) {
return BlocBuilder(
builder:(ctx, state) => AutoRouter.declerative(
routes: (_) => [
if(state == state1)
Route1()
if(state == state2)
Route2()
]
),
);
}
I give the AutoRouter a try. But I like the idea of the declarative router, I'll add this to my refactoring list. Do I see this right could I then just use a bloc build to return the page that is needed for each state?
Ignore me just saw the builder in your example.
Thank you very much @Milad-Akarie the AutoRouter works like a charm. I also found that my authentication setup from time to time just triggered and that also caused the main page to rerender. To refactor it to be a declarative route will be definitely the better solution and I will revisit that when I do a proper refactor with a bloc to deal with the navigation.
Hi, I have my main app routes nested with a wrapping route that contains my bloc providers. My initial route is a splash screen that handles the initial navigation depending on some data and replaces the splash screen with the correct route.
The problem comes when I try to push a new route to the stack because it always sends me back to the splash screen instead of the pushed page. Also, does it seem like my MainPage get's rebuilt what kills the bloc provider that I would need on other pages. Is there a way to get around this behaviour and keep the Main Page untouched when pushing new pages?
My configuration looks like this:
Thank you!