Created
December 15, 2025 18:04
-
-
Save maharatha/985963431418349ae52f70c4889db88b to your computer and use it in GitHub Desktop.
FA Login Experience
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import 'package:flutter/material.dart'; | |
| void main() { | |
| runApp(const AuthStoryboardApp()); | |
| } | |
| class AuthStoryboardApp extends StatelessWidget { | |
| const AuthStoryboardApp({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return MaterialApp( | |
| debugShowCheckedModeBanner: false, | |
| title: 'FA Auth Storyboard', | |
| theme: ThemeData( | |
| useMaterial3: true, | |
| colorSchemeSeed: const Color(0xFF2563EB), | |
| scaffoldBackgroundColor: const Color(0xFFF6F7FB), | |
| ), | |
| home: const EntryScreen(), | |
| ); | |
| } | |
| } | |
| /* ---------- SHARED UI ---------- */ | |
| class PageShell extends StatelessWidget { | |
| final String title; | |
| final Widget body; | |
| final bool showBack; | |
| const PageShell({ | |
| super.key, | |
| required this.title, | |
| required this.body, | |
| this.showBack = true, | |
| }); | |
| @override | |
| Widget build(BuildContext context) { | |
| return Scaffold( | |
| appBar: AppBar( | |
| title: Text(title, style: const TextStyle(fontWeight: FontWeight.w700)), | |
| leading: showBack | |
| ? IconButton( | |
| icon: const Icon(Icons.arrow_back), | |
| onPressed: () => Navigator.pop(context), | |
| ) | |
| : null, | |
| ), | |
| body: Center( | |
| child: ConstrainedBox( | |
| constraints: const BoxConstraints(maxWidth: 420), | |
| child: Padding( | |
| padding: const EdgeInsets.all(16), | |
| child: body, | |
| ), | |
| ), | |
| ), | |
| ); | |
| } | |
| } | |
| Widget primaryButton(BuildContext c, String label, Widget page) { | |
| return FilledButton( | |
| onPressed: () => Navigator.push(c, MaterialPageRoute(builder: (_) => page)), | |
| style: FilledButton.styleFrom(minimumSize: const Size.fromHeight(48)), | |
| child: Text(label), | |
| ); | |
| } | |
| Widget section(String title, String subtitle) { | |
| return Column( | |
| crossAxisAlignment: CrossAxisAlignment.start, | |
| children: [ | |
| Text(title, style: const TextStyle(fontSize: 22, fontWeight: FontWeight.bold)), | |
| const SizedBox(height: 6), | |
| Text(subtitle, style: TextStyle(color: Colors.black.withOpacity(0.6))), | |
| ], | |
| ); | |
| } | |
| /* ---------- SCREENS ---------- */ | |
| class EntryScreen extends StatelessWidget { | |
| const EntryScreen({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return PageShell( | |
| title: 'First Alert App', | |
| showBack: false, | |
| body: Column( | |
| crossAxisAlignment: CrossAxisAlignment.stretch, | |
| children: [ | |
| section('Welcome', 'Choose how you want to sign in'), | |
| const SizedBox(height: 24), | |
| primaryButton(context, 'Login with Email', const EmailLoginScreen()), | |
| const SizedBox(height: 12), | |
| primaryButton(context, 'Login with OTP', const OtpEmailScreen()), | |
| const SizedBox(height: 12), | |
| primaryButton(context, 'Login with SSO', const SsoScreen()), | |
| const SizedBox(height: 12), | |
| OutlinedButton( | |
| onPressed: () => Navigator.push( | |
| context, | |
| MaterialPageRoute(builder: (_) => const CreateAccountScreen()), | |
| ), | |
| child: const Text('Create Account'), | |
| ), | |
| ], | |
| ), | |
| ); | |
| } | |
| } | |
| /* ---------- EMAIL LOGIN ---------- */ | |
| class EmailLoginScreen extends StatelessWidget { | |
| const EmailLoginScreen({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return PageShell( | |
| title: 'Login with Email', | |
| body: Column( | |
| crossAxisAlignment: CrossAxisAlignment.stretch, | |
| children: [ | |
| section('Enter Email', 'Password will be entered on Auth0'), | |
| const SizedBox(height: 16), | |
| const TextField(decoration: InputDecoration(labelText: 'Email')), | |
| const SizedBox(height: 24), | |
| primaryButton(context, 'Continue', const Auth0PasswordScreen()), | |
| ], | |
| ), | |
| ); | |
| } | |
| } | |
| class Auth0PasswordScreen extends StatelessWidget { | |
| const Auth0PasswordScreen({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return PageShell( | |
| title: 'Auth0 – Password', | |
| body: Column( | |
| crossAxisAlignment: CrossAxisAlignment.stretch, | |
| children: [ | |
| section('Enter Password', 'This screen is hosted by Auth0'), | |
| const SizedBox(height: 16), | |
| const TextField( | |
| obscureText: true, | |
| decoration: InputDecoration(labelText: 'Password'), | |
| ), | |
| const SizedBox(height: 24), | |
| primaryButton(context, 'Login', const DashboardScreen()), | |
| ], | |
| ), | |
| ); | |
| } | |
| } | |
| /* ---------- OTP LOGIN ---------- */ | |
| class OtpEmailScreen extends StatelessWidget { | |
| const OtpEmailScreen({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return PageShell( | |
| title: 'Login with OTP', | |
| body: Column( | |
| crossAxisAlignment: CrossAxisAlignment.stretch, | |
| children: [ | |
| section('Enter Email', 'We will send a one-time code'), | |
| const SizedBox(height: 16), | |
| const TextField(decoration: InputDecoration(labelText: 'Email')), | |
| const SizedBox(height: 24), | |
| primaryButton(context, 'Send Code', const OtpCodeScreen()), | |
| ], | |
| ), | |
| ); | |
| } | |
| } | |
| class OtpCodeScreen extends StatelessWidget { | |
| const OtpCodeScreen({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return PageShell( | |
| title: 'Enter OTP', | |
| body: Column( | |
| crossAxisAlignment: CrossAxisAlignment.stretch, | |
| children: [ | |
| section('Check your email', 'Enter the 6-digit code'), | |
| const SizedBox(height: 16), | |
| const TextField(decoration: InputDecoration(labelText: 'OTP Code')), | |
| const SizedBox(height: 24), | |
| primaryButton(context, 'Verify', const ProfileScreen()), | |
| ], | |
| ), | |
| ); | |
| } | |
| } | |
| /* ---------- SSO ---------- */ | |
| class SsoScreen extends StatelessWidget { | |
| const SsoScreen({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return PageShell( | |
| title: 'Social Login', | |
| body: Column( | |
| crossAxisAlignment: CrossAxisAlignment.stretch, | |
| children: [ | |
| section('Continue with SSO', 'Google or Apple'), | |
| const SizedBox(height: 24), | |
| primaryButton(context, 'Continue with Google', const ProfileScreen()), | |
| const SizedBox(height: 12), | |
| primaryButton(context, 'Continue with Apple', const ProfileScreen()), | |
| ], | |
| ), | |
| ); | |
| } | |
| } | |
| /* ---------- CREATE ACCOUNT ---------- */ | |
| class CreateAccountScreen extends StatelessWidget { | |
| const CreateAccountScreen({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return PageShell( | |
| title: 'Create Account', | |
| body: Column( | |
| crossAxisAlignment: CrossAxisAlignment.stretch, | |
| children: [ | |
| section('Create Account', 'No password required'), | |
| const SizedBox(height: 16), | |
| const TextField(decoration: InputDecoration(labelText: 'First Name')), | |
| const SizedBox(height: 8), | |
| const TextField(decoration: InputDecoration(labelText: 'Last Name')), | |
| const SizedBox(height: 8), | |
| const TextField(decoration: InputDecoration(labelText: 'Email')), | |
| const SizedBox(height: 24), | |
| primaryButton(context, 'Continue', const CheckEmailScreen()), | |
| ], | |
| ), | |
| ); | |
| } | |
| } | |
| class CheckEmailScreen extends StatelessWidget { | |
| const CheckEmailScreen({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return PageShell( | |
| title: 'Check Your Email', | |
| body: Column( | |
| crossAxisAlignment: CrossAxisAlignment.stretch, | |
| children: [ | |
| section('Next Steps', 'If eligible, you will receive a temporary password'), | |
| const SizedBox(height: 24), | |
| primaryButton(context, 'Login with Temp Password', const Auth0PasswordChangeScreen()), | |
| ], | |
| ), | |
| ); | |
| } | |
| } | |
| class Auth0PasswordChangeScreen extends StatelessWidget { | |
| const Auth0PasswordChangeScreen({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return PageShell( | |
| title: 'Auth0 – Change Password', | |
| body: Column( | |
| crossAxisAlignment: CrossAxisAlignment.stretch, | |
| children: [ | |
| section('Set New Password', 'Required before login'), | |
| const SizedBox(height: 16), | |
| const TextField(obscureText: true, decoration: InputDecoration(labelText: 'New Password')), | |
| const SizedBox(height: 8), | |
| const TextField(obscureText: true, decoration: InputDecoration(labelText: 'Confirm Password')), | |
| const SizedBox(height: 24), | |
| primaryButton(context, 'Save', const DashboardScreen()), | |
| ], | |
| ), | |
| ); | |
| } | |
| } | |
| /* ---------- PROFILE ---------- */ | |
| class ProfileScreen extends StatelessWidget { | |
| const ProfileScreen({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return PageShell( | |
| title: 'Complete Profile', | |
| body: Column( | |
| crossAxisAlignment: CrossAxisAlignment.stretch, | |
| children: [ | |
| section('Profile Info', 'Required before continuing'), | |
| const SizedBox(height: 16), | |
| const TextField(decoration: InputDecoration(labelText: 'First Name')), | |
| const SizedBox(height: 8), | |
| const TextField(decoration: InputDecoration(labelText: 'Last Name')), | |
| const SizedBox(height: 8), | |
| const TextField(decoration: InputDecoration(labelText: 'Location')), | |
| const SizedBox(height: 24), | |
| primaryButton(context, 'Continue', const DashboardScreen()), | |
| ], | |
| ), | |
| ); | |
| } | |
| } | |
| /* ---------- DASHBOARD ---------- */ | |
| class DashboardScreen extends StatelessWidget { | |
| const DashboardScreen({super.key}); | |
| @override | |
| Widget build(BuildContext context) { | |
| return PageShell( | |
| title: 'Dashboard', | |
| showBack: false, | |
| body: Column( | |
| crossAxisAlignment: CrossAxisAlignment.stretch, | |
| children: [ | |
| section('You’re logged in', 'This represents FA App post-login'), | |
| const SizedBox(height: 24), | |
| FilledButton( | |
| onPressed: () { | |
| Navigator.pushAndRemoveUntil( | |
| context, | |
| MaterialPageRoute(builder: (_) => const EntryScreen()), | |
| (_) => false, | |
| ); | |
| }, | |
| child: const Text('Sign Out'), | |
| ), | |
| ], | |
| ), | |
| ); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment