Reputation: 11
I have a problem for which I haven't seen a solution anywhere yet.
I'm using go_route for routing, where I also use shellroute to generate a bottomnavigatorbar in some given paths, but I want it to work like for example on Instagram, so that when I have the functionality of a given page where the bottomnavigatorbar is generated, I want it to remember the given paths where it was before, so that it doesn't follow exactly the structure of go_route, so that when a user goes for example to /, then to /search and then to /profile, so when he clicks the back button, it first moves him to /search and then to /, but once he's in the / path, for example, he clicks on /search, again on /, so the back button from the / directory moves him to /search, just where he was before, I solve this in the bottomnavigation back_button_interceptor, where I check the back button and the popscope function, when I finally shut down the application, but the problem occurs when I'm in the / directory
This is a piece of my go_route `
const String rootRoute = '/';
final GlobalKey<NavigatorState> navigatorKey = GlobalKey();
final GoRouter router = GoRouter(
debugLogDiagnostics: true,
errorBuilder: (context, state) => ErrorScreen(state.error),
initialLocation: rootRoute,
navigatorKey: navigatorKey,
routes: <RouteBase>[
ShellRoute(
//navigatorKey: _rootNavigatorKey,
builder: (BuildContext context, GoRouterState state, Widget child) {
return MultiBlocProvider(
providers: [
BlocProvider.value(value: _authBloc),
BlocProvider.value(value: _authorizedTokenCubit),
BlocProvider.value(value: _signInUserCubit),
],
child: BlocBuilder<AuthorizedTokenCubit, AuthorizedTokenState>(
builder: (context, authState) {
if (authState is AuthorizedTokenSuccess) {
return BlocBuilder<SignInUserCubit, SignInUserState>(
builder: (context, SignInState) {
if (state.uri.path == '/' || state.uri.path == '/search' || (SignInState is SignInUserSuccess && state.uri.pathSegments.length == 1)) {
return ScaffoldWithNavBar(child: child);
} else {
return child; // No ScaffoldWithNavBar for WelcomePage
}
}
);
return child;
} else {
return child; // No ScaffoldWithNavBar for WelcomePage
}
},
),
);
},
routes: <RouteBase>[
GoRoute(
path: '/',
builder: (BuildContext context, GoRouterState state) {
return MultiBlocProvider(
providers: [
BlocProvider.value(value: _authBloc),
BlocProvider.value(value: _authorizedTokenCubit),
],
child: BlocBuilder<AuthorizedTokenCubit, AuthorizedTokenState>(
builder: (context, state) {
if (state is AuthorizedTokenSuccess) {
return HomePage();
} else {
return WelcomePage();
}
}));
},
routes: <RouteBase>[
GoRoute(
path: 'signin',
builder: (BuildContext context, GoRouterState state) {
return MultiBlocProvider(providers: [
BlocProvider.value(value: _authBloc),
], child: SignInPage());
},
routes: [
GoRoute(
path: 'forgottenpassword',
builder: (BuildContext context, GoRouterState state) {
return MultiBlocProvider(
providers: [
BlocProvider.value(value: _authBloc),
BlocProvider.value(value: _authorizedTokenCubit),
],
child: BlocBuilder<AuthorizedTokenCubit,
AuthorizedTokenState>(builder: (context, state) {
return ForgottenPasswordPage();
}));
},
),
]),
GoRoute(
path: 'forgottenpasswordlink',
builder: (BuildContext context, GoRouterState state) {
return MultiBlocProvider(providers: [
BlocProvider.value(value: _authBloc),
BlocProvider.value(value: _injectDataCubit),
], child: ForgottenPasswordLinkPage());
},
),
GoRoute(
path: 'search',
builder: (BuildContext context, GoRouterState state) {
// return MultiBlocProvider(providers: [
// BlocProvider.value(value: _searchCubit),
// ], child: Search());
return Search();
},
),
);
Where I implement ScaffoldWithNavBar which is bottomnavigation, this works fine for me, it creates where it should, the problem is though, in battomnavigation.dart
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:go_router/go_router.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:back_button_interceptor/back_button_interceptor.dart';
import '../../router/models/routes.dart';
class ScaffoldWithNavBar extends StatefulWidget {
/// Constructs an [ScaffoldWithNavBar].
final Widget child;
const ScaffoldWithNavBar({
required this.child,
super.key,
});
/// The widget to display in the body of the Scaffold.
/// In this sample, it is a Navigator.
@override
_ScaffoldWithNavBarState createState() => _ScaffoldWithNavBarState();
}
List<String> navigationHistory = ['/'];
class _ScaffoldWithNavBarState extends State<ScaffoldWithNavBar> {
int _selectedIndex = 0;
@override
void initState() {
super.initState();
// print('hoj');
// print(widget.child);
BackButtonInterceptor.add(myInterceptor);
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
_calculateSelectedIndex(context).then((index) {
setState(() {
_selectedIndex = index;
});
});
}
@override
void dispose() {
BackButtonInterceptor.remove(myInterceptor);
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
children: <Widget>[
PopScope(
canPop: false,
child: TextButton(
onPressed: () async {
// Your onPressed code here
},
child: Text('data'),
),
),
Expanded(child: widget.child)
],
),
bottomNavigationBar: BottomNavigationBar(
items: const <BottomNavigationBarItem>[
BottomNavigationBarItem(
icon: Icon(Icons.home),
label: 'Home',
),
BottomNavigationBarItem(
icon: Icon(Icons.search),
label: 'Find',
),
BottomNavigationBarItem(
icon: Icon(Icons.person),
label: 'My profile',
),
],
currentIndex: _selectedIndex,
selectedItemColor: Colors.blue, // Set the color for the selected item
//unselectedItemColor: Colors.grey, // Set the color for unselected items
onTap: (int idx) => _onItemTapped(idx, context),
),
);
}
bool myInterceptor(bool stopDefaultButtonEvent, RouteInfo info) {
print("BACK BUTTON!"); // Do some stuff.
// Get and remove the last item from navigationHistory
if (navigationHistory.isNotEmpty) {
String lastPath = navigationHistory.last;
print(lastPath);
GoRouter.of(context).go(lastPath);
navigationHistory.removeLast();
}else{
// SystemNavigator.pop();
}
print(navigationHistory);
return true;
}
Future<int> _calculateSelectedIndex(BuildContext context) async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final String? username = prefs.getString('username');
final String location = GoRouterState.of(context).uri.path;
if (location == '/') {
return 0;
}
if (location == '/search') {
return 1;
}
if(username != null){
if (location.contains(username)) {
return 2;
}else{
return 0;
}
}
return 0;
}
void _onItemTapped(int index, BuildContext context) async{
final SharedPreferences prefs = await SharedPreferences.getInstance();
final String? username = prefs.getString('username');
final String currentPath = GoRouterState.of(context).uri.path;
print(currentPath);
setState(() {
_selectedIndex = index;
// Ensure '/' is always the first entry in navigationHistory
if (!navigationHistory.contains('/')) {
navigationHistory.insert(0, '/');
}
// Remove currentPath if it already exists in navigationHistory to ensure uniqueness
if(currentPath != '/'){
navigationHistory.remove(currentPath);
}
// Insert currentPath at the beginning of navigationHistory
if (currentPath != '/') {
if (username != null)
if(!((index == 1 && currentPath == RoutePaths.search) || (index == 2 && currentPath == '/' + username))){
navigationHistory.insert(1, currentPath); // Insert after '/' if it's not already there
}
}
// Limit navigationHistory to 3 unique paths
if (navigationHistory.length > 3) {
navigationHistory.removeLast();
}
});
print(navigationHistory);
switch (index) {
case 0:
GoRouter.of(context).go(RoutePaths.home);
break;
case 1:
GoRouter.of(context).go(RoutePaths.search);
//context.pushReplacement(RoutePaths.search);
//GoRouter.of(context).go(RoutePaths.search);
break;
case 2:
if (username != null) {
context.push('/' + username);
} else {
GoRouter.of(context).go(RoutePaths.home);
}
break;
}
}
}
Here you can see my bottomnavigation code but the strange thing is that the whole function works as it should, when I comment out where I am inserting the page I am on, then it works as it should and in the current context the application doesn't close, but as soon as I include widget.child in there it doesn't work Expanded(child: widget.child)
I've tried many options but no matter what I've searched and tried different options, nothing works as it should, I use go_router: ^12.1.3
Upvotes: 1
Views: 184