I’m Odinachi, pronounced literally, and I am a member of the Flutter Lagos community. On our WhatsApp group an opportunity was shared, “Flutter/Dart internship at Invertase”. With a little dig into the company and team, I realized this is going to be a once in a lifetime opportunity. I applied and hoped for the best. On 14th of June, I got a very valuable gift! I was selected for the internship. I was so excited and couldn’t wait to start.
Words could not explain how joyous I felt, but that was just the beginning of what will be a bedrock of greatness! On the 21st of June, we had our on-boarding session, where we met our mentors and colleagues. In the session, we got the opportunity to meet Majid, Mais, Mike, Andrei, Volodymyr, Guillaume, and Elliot, who were our mentors. Ahmed, Beyza, Cagla, Donald (my buddy), Fatimah, Praynay, and Mo (my buddy too!) were my colleagues, and we were split up into teams and assigned Mentors who supervised and assigned us tasks.
FlutterFire UI:
My first assignment was to understand what FlutterFire UI was and how it works. FlutterFire is a helper for installing and managing Firebase in your Flutter applications. FlutterFire UI is a UI component that does the developer’s heavy lifting of Firebase authentication and provides template authentication UI to start with.
How to use FlutterFire UI:
During my two months at Invertase, I was tasked with demonstrating how FlutterFire UI works. So I would like to share what I learned by showing you how you can use FlutterFire UI with GoRouter for a seamless authentication process.
First, you need to have NodeJS installed on your machine. You can download it from here.
Then, you need to install the Firebase CLI. You can do this by running the following command in your terminal:
npm install -g firebase-tools
Then, install FlutterFire CLI as a global Dart package:
dart pub global activate flutterfire_cli
Then, create a new Flutter project:
flutter create flutterfire-ui-auth
Then, add the FlutterFire UI package to your pubspec.yaml
file:
flutter pub add flutterfire_ui
And the Firebase packages needed for authentication:
flutter pub add firebase_core
flutter pub add firebase_auth
Next, set-up your Firebase project. You can do this by running the following command:
flutterfire configure
Finally, for our tutorial, add the following packages:
flutter pub add flutter_dotenv
flutter pub add go_router
flutter pub add dio
flutter_dotenv
: this package will be used for saving our Google key used for Google authentication in an.env
file.
Create the following files namely:
auth_screen.dart
(this will house our authentication UI)home_screen.dart
(this will be our home screen)verify_email_screen.dart
(this will be our email verification screen)
Go to your main.dart
, and add the following code:
Future main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp(
options: DefaultFirebaseOptions.currentPlatform,
);
await dotenv.load(fileName: ".env");
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
@override
Widget build(BuildContext context) {
return MaterialApp.router(
routeInformationParser: router.routeInformationParser,
routerDelegate: router.routerDelegate,
theme: ThemeData(
backgroundColor: Colors.white,
inputDecorationTheme: InputDecorationTheme(
border: OutlineInputBorder(
borderRadius: BorderRadius.circular(8),
),
),
outlinedButtonTheme: OutlinedButtonThemeData(
style: ButtonStyle(
padding: MaterialStateProperty.all(
const EdgeInsets.all(14),
),
//these controls the button close of the entire apps if no color was specified
backgroundColor: MaterialStateProperty.all(Colors.blue),
foregroundColor: MaterialStateProperty.all(Colors.white),
),
),
),
);
}
}
Afterwards, create a router instance to manage your routes
final GoRouter router = GoRouter(
//checks for the initial page to show the user based on the user details
initialLocation: FirebaseAuth.instance.currentUser?.email == null
? "/"
: FirebaseAuth.instance.currentUser?.emailVerified != false
? "/verify_email"
: "/home",
routes: [
GoRoute(
path: '/',
builder: (BuildContext context, GoRouterState state) =>
const AuthScreen(),
),
GoRoute(
path: '/home',
builder: (BuildContext context, GoRouterState state) {
return AuthFlowBuilder(
listener: (oldState, newState, controller) {
if (newState is! SignedIn) {
context.go('/');
}
},
builder: (context, state, controller, _) {
return const HomeScreen();
},
);
},
),
GoRoute(
path: '/verify_email',
builder: (BuildContext context, GoRouterState state) =>
const VerifyEmailScreen(),
),
],
redirect: (state) {
User? user = FirebaseAuth.instance.currentUser;
final currentRoute = state.subloc;
if (user == null) {
return currentRoute == "/" ? null : "/";
} else if (user.emailVerified == true) {
return currentRoute == '/verify_email' ? null : '/verify_email';
} else {
return currentRoute == "/home" ? null : "/home";
}
},
debugLogDiagnostics: true,
);
The code above manages your routes so if the user is logged in, they’ll be moved to the home page else they’ll be asked to authenticate.
Next, in your auth_screen.dart
, add the following code:
class AuthScreen extends StatelessWidget {
const AuthScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return SignInScreen(
oauthButtonVariant: OAuthButtonVariant.icon_and_text,
resizeToAvoidBottomInset: true,
providerConfigs: [
const EmailProviderConfiguration(),
GoogleProviderConfiguration(
clientId: dotenv.get("GOOGLE_KEY", fallback: ""),
)
],
actions: [
AuthStateChangeAction((context, AuthState state) {
if (state is SignedIn) {
context.go("/home");
}
})
],
);
}
Actions are basically what you could call events, so you handle them based on what event is being triggered at a time and providers are methods in which you want the authentication to be done
Next, in your verify_email_screen.dart
, you should have the following code:
class VerifyEmailScreen extends StatelessWidget {
const VerifyEmailScreen({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return EmailVerificationScreen(
actions: [
//this callback is called immediately email is verified
EmailVerified(() {
context.go("/home");
}),
],
);
}
}
In the code above, we want to move the user to the home screen when their email is verified.
Next, in your home_screen.dart
you should have
class HomeScreen extends StatelessWidget {
const HomeScreen({Key? key}) : super(key: key);
static User? user = FirebaseAuth.instance.currentUser;
@override
Widget build(BuildContext context) {
Future handleDeleteUser() async {
await FirebaseAuth.instance.currentUser
?.delete(); // this also signs out the user
context.go("/");
}
return Scaffold(
body: SafeArea(
child: Stack(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
InkWell(
onTap: handleDeleteUser,
child: const Padding(
padding: EdgeInsets.all(10.0),
child: Text(
"Delete Account",
style: TextStyle(
color: Colors.red,
fontWeight: FontWeight.w600,
),
),
),
),
],
),
Center(
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
Text(
user?.email ?? '',
style: const TextStyle(
fontSize: 20,
),
),
TextButton(
onPressed: () async {
await FlutterFireUIAuth.signOut();
context.go("/");
},
child: const Text('Logout'),
)
],
),
),
],
),
),
);
}
}
In the code above, users can log out or delete their account if they want to.
Finally, in your root directory, create a .env
file and assign a GOOGLE_KEY
to the value of your Google key like this:
GOOGLE_KEY={Google key}
YOu can get your Google Key by going to the Firebase Console -> Authetication -> Add provider -> Google -> Web client ID
When all of these are connected, this is the outcome:
You can get the full code here.
Other activities in the internship program
- we had a session with Lukas Klingsbo where we discussed Flame and what it is, and we built a simple game with it; in the future, I’ll be detailing how it can be used from my experience.
- we had a session with Remi Rousselet where he walked us through Riverpod. It was quite an interesting session for me because Remi is my mentor, it felt like learning at a master’s feat, and I automatically adapted Riverpod as my default state management after that lecture… who wouldn’t?😂😂
My upcoming goals
From now on, I’ll be active in the open source community for Flutter and contribute as much as possible; I already have a mentor to guide me on that.
Credits
Special thanks to Andrei Lesnitsky for being such a great mentor and my go-to person throughout the program. He always made time to attend to my inquiries and give advice and corrections on every step.
My sincere gratitude to Majid Hajian for the advice and encouragement; your presence was like a light that exposed us to many possibilities; thank you for challenging us.
All of this wouldn’t be possible without Invertase and the beautiful people behind the company; I’m super grateful for the opportunity, and to Guillaume, Mais and Volodymyr, you guys are amazing, and I’m proud to have spent two months with you.
Mo and Donald, you’re like a family Invertase gave me; I’m rooting for you and the rest of my colleagues; you all rock.
Advices for Prospective Interns
After I was announced, I got looks of messages asking how the application process was and what my recommendations would be, so let me put it out here.
- It’ll be of excellent service if you understand the basics of Flutter and Dart.
- You should have an evident passion for Open Source and be open-minded to learning new things.
- You should be good enough in writing to convince anyone about your passion for Open Source and why you choose Open Source.
- Be ready to do the work, not just the hours.
Thank you for reading!