blob: 868944c0b6392dc418610683328e04fe40c85745 [file] [log] [blame]
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
// This scenario demonstrates how to use redirect to handle a sign-in flow.
//
// The GoRouter.redirect method is called before the app is navigate to a
// new page. You can choose to redirect to a different page by returning a
// non-null URL string.
/// The login information.
class LoginInfo extends ChangeNotifier {
/// The username of login.
String get userName => _userName;
String _userName = '';
/// Whether a user has logged in.
bool get loggedIn => _userName.isNotEmpty;
/// Logs in a user.
void login(String userName) {
_userName = userName;
notifyListeners();
}
/// Logs out the current user.
void logout() {
_userName = '';
notifyListeners();
}
}
void main() => runApp(App());
/// The main app.
class App extends StatelessWidget {
/// Creates an [App].
App({super.key});
final LoginInfo _loginInfo = LoginInfo();
/// The title of the app.
static const String title = 'GoRouter Example: Redirection';
// add the login info into the tree as app state that can change over time
@override
Widget build(BuildContext context) => ChangeNotifierProvider<LoginInfo>.value(
value: _loginInfo,
child: MaterialApp.router(
routerConfig: _router,
title: title,
debugShowCheckedModeBanner: false,
),
);
late final GoRouter _router = GoRouter(
routes: <GoRoute>[
GoRoute(
path: '/',
builder: (BuildContext context, GoRouterState state) =>
const HomeScreen(),
),
GoRoute(
path: '/login',
builder: (BuildContext context, GoRouterState state) =>
const LoginScreen(),
),
],
// redirect to the login page if the user is not logged in
redirect: (BuildContext context, GoRouterState state) {
// if the user is not logged in, they need to login
final bool loggedIn = _loginInfo.loggedIn;
final bool loggingIn = state.matchedLocation == '/login';
if (!loggedIn) {
return '/login';
}
// if the user is logged in but still on the login page, send them to
// the home page
if (loggingIn) {
return '/';
}
// no need to redirect at all
return null;
},
// changes on the listenable will cause the router to refresh it's route
refreshListenable: _loginInfo,
);
}
/// The login screen.
class LoginScreen extends StatelessWidget {
/// Creates a [LoginScreen].
const LoginScreen({super.key});
@override
Widget build(BuildContext context) => Scaffold(
appBar: AppBar(title: const Text(App.title)),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () {
// log a user in, letting all the listeners know
context.read<LoginInfo>().login('test-user');
// router will automatically redirect from /login to / using
// refreshListenable
},
child: const Text('Login'),
),
],
),
),
);
}
/// The home screen.
class HomeScreen extends StatelessWidget {
/// Creates a [HomeScreen].
const HomeScreen({super.key});
@override
Widget build(BuildContext context) {
final LoginInfo info = context.read<LoginInfo>();
return Scaffold(
appBar: AppBar(
title: const Text(App.title),
actions: <Widget>[
IconButton(
onPressed: info.logout,
tooltip: 'Logout: ${info.userName}',
icon: const Icon(Icons.logout),
)
],
),
body: const Center(
child: Text('HomeScreen'),
),
);
}
}