Headers & Footers
There are two ways you can add custom headers and footers to your Android Authenticator.
First, you can add a single header/footer to every screen in the Authenticator. The following example adds an image to the header and a copyright to the footer:
Authenticator(
headerContent = {
Box(
modifier = Modifier.size(80.dp).align(Alignment.CenterHorizontally)
) {
Image(
painter = painterResource(R.drawable.amplify),
contentDescription = null,
)
}
},
footerContent = {
Text(
"© All Rights Reserved",
modifier = Modifier.align(Alignment.CenterHorizontally)
)
}
) {
// ...
}
Alternatively, you can add a header or a footer to an individual screen. More detail on fully customizing the UI of individual screens is in Full UI Customization. This example uses an inline lambda to add a Divider
component to the header on the sign up screen.
Authenticator(
signUpContent = { signUpState ->
SignUp(
state = signUpState,
headerContent = {
Column {
Text(
style = MaterialTheme.typography.titleLarge,
text = stringResource(R.string.amplify_ui_authenticator_title_signup)
)
Divider()
}
}
)
}
) {
// ...
}
or by using a @Composable
function:
Authenticator(
signUpContent = { SignUpWithCustomHeader() },
signInContent = { CustomSignIn() }
// ...etc
) {
// ...
}
Internationalization (I18n)
The Android Authenticator component uses string resources for all of its labels, so internationalization can be accomplished by providing a custom strings.xml
file. For example, in a values-fr/strings.xml
file you can have lines like the following to provide custom translations for all Authenticator strings:
<string name="amplify_ui_authenticator_field_warn_existing">Désolé, c\'est déjà pris</string>
Labels & Text
Using the same techniques as Internationalization (I18n), you can customize the labels (hints) and text of the components. Every string defined by the library is prefixed with amplify_ui_authenticator_
and strings adhere to a hierarchical naming convention to help identify its usage. All such strings can be found in the authenticator/src/main/res/values
folder.
For example, here's a string from the library:
<string name="amplify_ui_authenticator_field_warn_existing">%s already exists</string>
You can change this string by overriding the string in your application's default resources:
<string name="amplify_ui_authenticator_field_warn_existing">Sorry, this is already taken</string>
Sign Up Field Order
The Authenticator allows a custom order of sign up fields on the Sign Up page.
Order is determined by a signUpForm
@Compose
block that is passed into the Authenticator state.
In the example below the order will be set as email
, username
, password
and finally confirm_password
.
val state = rememberAuthenticatorState(
signUpForm = {
email()
username()
password()
confirmPassword()
}
)
Form Field Customization
The Authenticator allows for customization of multiple aspects of the form fields. The sections below will describe several use cases and how to modify the appropriate fields.
Overall, you can customize the hint or label of any input as described in the labels and placeholder section.
Additionally, when using a custom Sign Up form as described in Sign Up Field Order, you can create fields with custom labels and hints, as well as specify whether the field is required, or pass your own custom validator.
Updating labels, hints, setting required and adding validators
The following example customizes the Sign Up page by:
- Making the profile field optional.
- Customizing the website field (by adding a
text()
field and giving it thekey
FieldKey.Website
):- Adding a custom label.
- Adding a custom hint.
- Adding a custom validator.
- Adding a custom bio text field.
- Adding a custom terms of service checkbox.
Note: On the sign in page the input name is always username
, regardless of the login mechanism type.
val state = rememberAuthenticatorState(
signUpForm = {
username()
password()
confirmPassword()
email()
profile(required = false)
text(
key = FieldKey.Website,
label = "Website",
hint = "Put your website here",
required = true,
validator = {
if (!content.contains("example.com")) {
FieldError.Custom("Your website must have a domain of example.com")
} else {
null
}
}
)
text(
key = FieldKey.Custom("bio"),
label = "Bio",
maxLines = 3
)
custom(
key = FieldKey.Custom("terms"),
label = "Service Terms",
validator = {
if (!content.toBoolean()) {
FieldError.Custom("You must agree to the terms of service")
} else null
}
) {
Row(
modifier = Modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(8.dp)
) {
Checkbox(
checked = fieldState.content.toBoolean(),
onCheckedChange = { fieldState.content = it.toString() },
)
Text("I agree to the terms of service")
}
}
}
)
Theming
By default, the Amplify Authenticator uses your app's Material theme for its styling. Any customizations you make to colors, buttons, input widgets, etc. will be reflected in the Authenticator.
Below is an example with custom themes for the page titles, form fields, and elevated buttons.
private val DarkColorScheme = darkColorScheme(
primary = Purple80,
secondary = PurpleGrey80,
tertiary = Pink80
)
private val LightColorScheme = lightColorScheme(
primary = Purple40,
secondary = PurpleGrey40,
tertiary = Pink40
/* Other default colors to override
background = Color(0xFFFFFBFE),
surface = Color(0xFFFFFBFE),
onPrimary = Color.White,
onSecondary = Color.White,
onTertiary = Color.White,
onBackground = Color(0xFF1C1B1F),
onSurface = Color(0xFF1C1B1F),
*/
)
@Composable
fun AppTheme(
useDarkTheme: Boolean = isSystemInDarkTheme(),
content: @Composable () -> Unit
) {
val colors = if (!useDarkTheme) {
LightColorScheme
} else {
DarkColorScheme
}
MaterialTheme(
colorScheme = colors,
content = content
)
}
With usage:
AppTheme() {
Authenticator(...) {
...
}
}
Full UI Customization
In addition to customizing form fields and theming, you can also build a custom UI for one or more of the authenticator steps using a combination of prebuilt widgets from the amplify_authenticator
package, and widgets that you build yourself. This can be used for simple use cases, such as adding a logo to the sign in screen, as well as more complex use cases.
The Authenticator supports fully replacing the UI for any particular screen. Every screen has an associated State
instance that can be used to implement custom UI. Below is an example of how you can use signInContent
to customize the Sign In screen, replacing the username and password text fields, as well as the submit button.
Authenticator(
signInContent = { state ->
val scope = rememberCoroutineScope()
Column {
val username = state.form.fields[FieldKey.Username]!!
val password = state.form.fields[FieldKey.Password]!!
// Replace default UI with completely custom UI
TextField(
placeholder = { Text("Username") },
value = username.state.content,
onValueChange = { userName.state.content = it }
)
TextField(
placeholder = { Text("Password") },
value = password.state.content,
onValueChange = { password.state.content = it }
)
Button(onClick = { scope.launch { state.signIn() } }) {
Text("Sign In")
}
// Or reuse Authenticator's composables
SignInFooter(state)
}
}
) {
// ...
}