Currently I have a StreamBuilder switching between a HomePage
and LandingPage
depending on the current auth state. The issue I have encountered is that I cannot pop the stack to the original /landing
directory on a state change. This means that when a user logs in, the AuthPage
remains on the top of the stack and the StreamBuilder builds the HomePage
underneath.
AuthGate
class AuthGate extends StatelessWidget {
const AuthGate({super.key});
@override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (context, snapshot) {
return snapshot.hasData ? const HomePage() : const LandingPage();
},
);
}
}
LandingPage This pushes the AuthPage to the stack.
class LandingPage extends StatelessWidget {
const LandingPage({super.key});
...
Row(
children: <Widget>[
FloatingActionButton.extended(
heroTag: UniqueKey(),
onPressed: () {
context.push('/auth');
},
label: const Text('Get started'),
),
FloatingActionButton.extended(
heroTag: UniqueKey(),
onPressed: () {
context.push('/auth');
},
label: const Text('Log in'),
),
],
)
...
}
}
Note how the AuthPage
remains on the top of the stack but the Widget under StreamBuilder
changes to the HomePage
(This is my first Stack question so please feel free to ask me to amend any information etc.)
If you are using GoRouter, then what you want to achieve should be done through GoRouter similarly to this:
GoRouter(
refreshListenable:
GoRouterRefreshListenable(FirebaseAuth.instance.authStateChanges()),
initialLocation: '/auth',
routes: <GoRoute>[
GoRoute(
path: '/landing',
name: 'landing',
builder: (context, state) {
return LandingPage()
},
routes: [
GoRoute(
path: 'auth',
name: 'auth',
builder: (context, state) => const AuthPage(),
),
],
),
GoRoute(
path: '/home',
name: 'home',
builder: (context, state) => const HomePage(),
),
],
errorBuilder: (context, state) {
return const Scaffold(
body: Text('404'),
);
},
redirect: (context, state) async {
final userRepo = injector.get<UserRepository>();
final user = FirebaseAuth.instance;
const authPaths = [
'/landing',
'/landing/auth',
];
bool isAuthPage = authPaths.contains(state.subloc);
if(user != null) {
if (isAuthPage) {
return '/home';
}
}
if(!isAuthPage) {
return '/auth';
}
return null;
},
);
class GoRouterRefreshListenable extends ChangeNotifier {
GoRouterRefreshListenable(Stream stream) {
notifyListeners();
_subscription = stream.asBroadcastStream().listen(
(_) {
notifyListeners();
},
);
}
late final StreamSubscription _subscription;
@override
void dispose() {
_subscription.cancel();
super.dispose();
}
}
Please also read documentation on of GoRouter.