blob: 3dc0c109b3a03c4bbfe703af99adeea66c7eb5d4 [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:adaptive_navigation/adaptive_navigation.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:package_info_plus/package_info_plus.dart';
void main() => runApp(App());
/// The main app.
class App extends StatelessWidget {
/// Creates an [App].
App({Key? key}) : super(key: key);
/// The title of the app.
static const String title = 'GoRouter Example: Shared Scaffold';
@override
Widget build(BuildContext context) => MaterialApp.router(
routeInformationProvider: _router.routeInformationProvider,
routeInformationParser: _router.routeInformationParser,
routerDelegate: _router.routerDelegate,
title: title,
);
late final GoRouter _router = GoRouter(
debugLogDiagnostics: true,
routes: <GoRoute>[
GoRoute(
path: '/',
builder: (BuildContext context, GoRouterState state) =>
_build(const Page1View()),
),
GoRoute(
path: '/page2',
builder: (BuildContext context, GoRouterState state) =>
_build(const Page2View()),
),
],
errorBuilder: (BuildContext context, GoRouterState state) =>
_build(ErrorView(state.error!)),
// use the navigatorBuilder to keep the SharedScaffold from being animated
// as new pages as shown; wrappiong that in single-page Navigator at the
// root provides an Overlay needed for the adaptive navigation scaffold and
// a root Navigator to show the About box
navigatorBuilder:
(BuildContext context, GoRouterState state, Widget child) => Navigator(
onPopPage: (Route<dynamic> route, dynamic result) {
route.didPop(result);
return false; // don't pop the single page on the root navigator
},
pages: <Page<dynamic>>[
MaterialPage<void>(
child: state.error != null
? ErrorScaffold(body: child)
: SharedScaffold(
selectedIndex: state.subloc == '/' ? 0 : 1,
body: child,
),
),
],
),
);
// wrap the view widgets in a Scaffold to get the exit animation just right on
// the page being replaced
Widget _build(Widget child) => Scaffold(body: child);
}
/// A scaffold with multiple pages.
class SharedScaffold extends StatefulWidget {
/// Creates a shared scaffold.
const SharedScaffold({
required this.selectedIndex,
required this.body,
Key? key,
}) : super(key: key);
/// The selected index
final int selectedIndex;
/// The body of the page.
final Widget body;
@override
State<SharedScaffold> createState() => _SharedScaffoldState();
}
class _SharedScaffoldState extends State<SharedScaffold> {
@override
Widget build(BuildContext context) => AdaptiveNavigationScaffold(
selectedIndex: widget.selectedIndex,
destinations: const <AdaptiveScaffoldDestination>[
AdaptiveScaffoldDestination(title: 'Page 1', icon: Icons.first_page),
AdaptiveScaffoldDestination(title: 'Page 2', icon: Icons.last_page),
AdaptiveScaffoldDestination(title: 'About', icon: Icons.info),
],
appBar: AdaptiveAppBar(title: const Text(App.title)),
navigationTypeResolver: (BuildContext context) =>
_drawerSize ? NavigationType.drawer : NavigationType.bottom,
onDestinationSelected: (int index) async {
// if there's a drawer, close it
if (_drawerSize) {
Navigator.pop(context);
}
switch (index) {
case 0:
context.go('/');
break;
case 1:
context.go('/page2');
break;
case 2:
final PackageInfo packageInfo = await PackageInfo.fromPlatform();
showAboutDialog(
context: context,
applicationName: packageInfo.appName,
applicationVersion: 'v${packageInfo.version}',
applicationLegalese: 'Copyright © 2022, Acme, Corp.',
);
break;
default:
throw Exception('Invalid index');
}
},
body: widget.body,
);
bool get _drawerSize => MediaQuery.of(context).size.width >= 600;
}
/// The content of the first page.
class Page1View extends StatelessWidget {
/// Creates a [Page1View].
const Page1View({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () => context.go('/page2'),
child: const Text('Go to page 2'),
),
],
),
);
}
/// The content of the second page.
class Page2View extends StatelessWidget {
/// Creates a [Page2View].
const Page2View({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) => Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
ElevatedButton(
onPressed: () => context.go('/'),
child: const Text('Go to home page'),
),
],
),
);
}
/// The error scaffold.
class ErrorScaffold extends StatelessWidget {
/// Creates an [ErrorScaffold]
const ErrorScaffold({
required this.body,
Key? key,
}) : super(key: key);
/// The body of this scaffold.
final Widget body;
@override
Widget build(BuildContext context) => Scaffold(
appBar: AdaptiveAppBar(title: const Text('Page Not Found')),
body: body,
);
}
/// A view to display error message.
class ErrorView extends StatelessWidget {
/// Creates an [ErrorView].
const ErrorView(this.error, {Key? key}) : super(key: key);
/// The error to display.
final Exception error;
@override
Widget build(BuildContext context) => Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
SelectableText(error.toString()),
TextButton(
onPressed: () => context.go('/'),
child: const Text('Home'),
),
],
),
);
}