amplify_authenticator 0.1.0-rc.3 copy "amplify_authenticator: ^0.1.0-rc.3" to clipboard
amplify_authenticator: ^0.1.0-rc.3 copied to clipboard

outdated

A prebuilt sign in/sign up experience for Amplify Auth.

example/lib/main.dart

import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
import 'package:amplify_authenticator/amplify_authenticator.dart';
import 'package:amplify_authenticator_example/localized_country_resolver.dart';
import 'package:amplify_flutter/amplify_flutter.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';

import 'amplifyconfiguration.dart';
import 'localized_button_resolver.dart';

void main() {
  runApp(const MyApp());
}

class MyApp extends StatefulWidget {
  const MyApp({Key? key}) : super(key: key);

  @override
  State<MyApp> createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  @override
  void initState() {
    super.initState();
    _configureAmplify();
  }

  /// When using the Authenticator, configuration of Amplify is still the
  /// responsibility of the developer. This allows you the opportunity to
  /// customize plugin options and add/remove them as needed.
  void _configureAmplify() async {
    try {
      await Amplify.addPlugin(AmplifyAuthCognito());
      await Amplify.configure(amplifyconfig);
      print('Successfully configured');
    } on Exception catch (e) {
      print('Error configuring Amplify: $e');
    }
  }

  /// Our custom username validator, which ensures that all usernames contain
  /// the word "amplify".
  String? _validateUsername(UsernameInput? input) {
    final username = input?.username;
    if (username == null || username.isEmpty) {
      return 'Username cannot be empty';
    }

    bool containsAmplify = username.contains('amplify');
    if (!containsAmplify) {
      return 'Username needs to include amplify';
    }

    return null;
  }

  @override
  Widget build(BuildContext context) {
    // First, we set up the custom localizations for Authenticator buttons by
    // creating a custom resolver which conforms to the `ButtonResolver` class
    // from the Authenticator library.
    //
    // In addition to ButtonResolver, which handles the labels for buttons, there
    // are also resolvers for input fields, screen titles, and navigation-related
    // items, all of which can be customized as well. To keep this demo simple,
    // we only specify a custom button resolver, which automatically configures
    // the default for the others.
    const stringResolver = AuthStringResolver(
      buttons: LocalizedButtonResolver(),
      countries: LocalizedCountryResolver(),
    );

    // We wrap our MaterialApp in an Authenticator component. This component
    // handles all the screens and logic whenever the user is signed out. Once
    // the user is signed in, the Authenticator will use your MaterialApp's
    // navigator to show the correct screen.
    return Authenticator(
      stringResolver: stringResolver,
      onException: (exception) {
        print('[ERROR]: $exception');
      },

      // Next, we create a custom Sign Up form which uses our custom username
      // validator.
      signUpForm: SignUpForm.custom(
        fields: [
          SignUpFormField.username(
            validator: _validateUsername,
          ),
          SignUpFormField.password(),
          SignUpFormField.passwordConfirmation(),
          SignUpFormField.address(
            required: false,
          ),
        ],
      ),

      // Your MaterialApp should be the child of the Authenticator.
      child: MaterialApp(
        title: 'Authenticator Demo',
        theme: ThemeData.light(),
        darkTheme: ThemeData.dark(),
        themeMode: ThemeMode.system,
        debugShowCheckedModeBanner: false,

        // These lines enable our custom localizations specified in the lib/l10n
        // directory, which will be used later to customize the values displayed
        // in the Authenticator component.
        localizationsDelegates: const [
          AppLocalizations.delegate,
        ],
        supportedLocales: const [
          Locale('en'), // English
          Locale('es'), // Spanish
        ],

        // The Authenticator component must wrap your Navigator component which
        // can be done using the `builder` method.
        builder: Authenticator.builder(),
        initialRoute: '/routeA',
        routes: {
          '/routeA': (BuildContext context) => const RouteA(),
          '/routeB': (BuildContext context) => const RouteB(),
        },
      ),
    );
  }
}

/// The screen which is shown once the user is logged in. We can use [SignOutButton]
/// from the Authenticator library anywhere in our app to provide a pre-configured
/// sign out experience. Alternatively, we can call [Amplify.Auth.signOut] which
/// will also notify the Authenticator.
class RouteA extends StatelessWidget {
  const RouteA({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Route A'),
      ),
      body: Center(
        child: Column(
          children: [
            ElevatedButton(
              onPressed: () =>
                  Navigator.of(context).pushReplacementNamed('/routeB'),
              child: const Text('Goto Route B'),
            ),
            const SizedBox(height: 20),
            const SignOutButton(),
          ],
        ),
      ),
    );
  }
}

class RouteB extends StatelessWidget {
  const RouteB({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Route B'),
      ),
      body: Center(
        child: Column(
          children: [
            ElevatedButton(
              onPressed: () =>
                  Navigator.of(context).pushReplacementNamed('/routeA'),
              child: const Text('Goto Route A'),
            ),
            const SizedBox(height: 20),
            const SignOutButton(),
          ],
        ),
      ),
    );
  }
}