
Build App Components
Build App Components êŽë š
Drawer
The Drawer is a side panel that slides in from the left (by default) and provides navigation options for the user. Itâs a great way to organize your appâs sections without crowding the main screen.
In our app, the drawer will include links to the Request recipe screen, Profile, Logout, and languages for authenticated users.
In the lib/components/
drawer.dart
file, add the code below:
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:shared_preferences/shared_preferences.dart';
import '../screens/profile.dart';
import '../screens/requestRecipe.dart';
class CustomDrawer extends StatefulWidget {
_CustomDrawerState createState() => _CustomDrawerState();
}
class _CustomDrawerState extends State<CustomDrawer> {
bool _isAuthenticated = false;
String? _username;
String? _userId;
void initState() {
super.initState();
_checkAuthentication();
}
Future<void> _checkAuthentication() async {
final prefs = await SharedPreferences.getInstance();
setState(() {
_isAuthenticated = prefs.containsKey('jwt');
_username = prefs.getString('username');
_userId = prefs.getString('userId');
});
}
void _navigateToLogin() {
Navigator.pushReplacementNamed(context, '/login');
}
Future<void> _logout() async {
final prefs = await SharedPreferences.getInstance();
await prefs.clear();
setState(() {
_isAuthenticated = false;
_username = null;
_userId = null;
});
Navigator.pushReplacementNamed(context, '/login');
}
void _changeLanguage(Locale locale) {
context.setLocale(locale);
}
Widget build(BuildContext context) {
return Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: [
DrawerHeader(
decoration: BoxDecoration(
color: Colors.blue,
),
child: Text(
_isAuthenticated ? tr('hello', namedArgs: {'username': _username ?? ''}) : tr('welcome'),
style: TextStyle(
color: Colors.white,
fontSize: 24,
),
),
),
if (_isAuthenticated)
ListTile(
leading: Icon(Icons.request_page),
title:Text(tr('request_recipe')),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => RecipeRequestScreen()),
);
},
),
if (_isAuthenticated)
ListTile(
leading: const Icon(Icons.person),
title: Text(tr('profile')),
onTap: () {
if (_userId != null) {
Navigator.push(
context,
MaterialPageRoute(builder: (context) => ProfileScreen()),
);
}
},
),
if (_isAuthenticated)
ListTile(
leading: Icon(Icons.logout),
title: Text(tr('logout')),
onTap: _logout,
)
else
ListTile(
leading: Icon(Icons.login),
title: Text(tr('login')),
onTap: _navigateToLogin,
),
Divider(),
ListTile(
leading: SizedBox(
width: 24.0,
height: 24.0,
child: Image.asset(
'assets/images/en-flag.jpg',
),
),
title: Text(tr('english')),
onTap: () {
Navigator.pop(context);
_changeLanguage(Locale('en'));
},
),
ListTile(
leading: SizedBox(
width: 24.0,
height: 24.0,
child: Image.asset(
'assets/images/fr-flag.jpg',
),
),
title: Text(tr('french')),
onTap: () {
Navigator.pop(context);
_changeLanguage(Locale('fr', 'FR'));
},
),
ListTile(
leading: SizedBox(
width: 24.0,
height: 24.0,
child: Image.asset(
'assets/images/ja-flag.jpg',
),
),
title: Text(tr('japanese')),
onTap: () {
Navigator.pop(context);
_changeLanguage(Locale('ja', 'JP'));
},
),
],
),
);
}
}
The CustomDrawer
gives users access to different parts of the app and lets them switch languages. It updates its content based on the user's login status. Logged-in users see options like âRequest a Recipe,â âProfile,â and âLogout,â while guests only see a âLoginâ option. It personalizes the user experience by greeting logged-in users with their username.
It also includes a language switcher with flag icons for English, French, and Japanese, powered by the easy_localization
package. This allows users to change the appâs language instantly.
On startup, the drawer checks the user's authentication status using SharedPreferences
and adjusts the UI accordingly. Navigation is handled with Navigator
, enabling smooth transitions to different screens based on the selected menu item.
AppBar
The AppBar is the top bar of your appâs screen. It typically contains the appâs title, a back button (if needed), and sometimes actions like search, settings, or a language toggle. In our multilingual recipe app, weâll use the AppBar
to show the current page title and allow easy navigation through the drawer.
In the lib/components/
appBar.dart
file, add the code below:
import 'package:flutter/material.dart';
/// A customizable AppBar for the Recipe application.
///
/// This AppBar allows for setting a title, actions, a leading widget,
/// centering the title, background color, and elevation.
class RecipeBar extends StatelessWidget implements PreferredSizeWidget {
final String title;
final List<Widget>? actions;
final Widget? leading;
final bool centerTitle;
final Color? backgroundColor;
final double elevation;
const RecipeBar({
required this.title,
this.actions,
this.leading,
this.centerTitle = true,
this.backgroundColor,
this.elevation = 4.0,
Key? key,
}) : super(key: key);
Widget build(BuildContext context) {
return AppBar(
title: Text(title),
actions: actions,
leading: leading,
centerTitle: centerTitle,
backgroundColor: backgroundColor,
elevation: elevation,
);
}
Size get preferredSize => const Size.fromHeight(kToolbarHeight);
}
The AppBar uses a StatelessWidget
since it does not manage any state that changes over time. It implements the PreferredSizeWidget
interface, which is necessary for AppBar customization in Flutter.
The constructor of the RecipeBar
class takes several parameters to customize the AppBar. The title
parameter is required, while the others are optional with default values. The actions
parameter allows adding widgets like buttons for login, language switching, or simply navigating to another screen of the app.
In the build
method, the AppBar is constructed using the provided parameters. The preferredSize
getter returns the preferred height of the AppBar, which is set to the standard toolbar height using kToolbarHeight
. This class provides a flexible and reusable AppBar component for the Recipe application, enabling easy customization and consistent UI design across different screens.