1515
1616package com.amplifyframework.ui.authenticator.strings
1717
18+ import android.annotation.SuppressLint
1819import androidx.compose.runtime.Composable
1920import androidx.compose.runtime.ReadOnlyComposable
20- import androidx.compose.ui.ExperimentalComposeUiApi
21+ import androidx.compose.ui.platform.LocalContext
2122import androidx.compose.ui.res.pluralStringResource
2223import androidx.compose.ui.res.stringResource
2324import com.amplifyframework.auth.AuthException
@@ -27,8 +28,13 @@ import com.amplifyframework.ui.authenticator.forms.FieldError
2728import com.amplifyframework.ui.authenticator.forms.FieldKey
2829import com.amplifyframework.ui.authenticator.forms.PasswordError
2930import com.amplifyframework.ui.authenticator.locals.LocalStringResolver
31+ import com.amplifyframework.ui.authenticator.util.toResourceName
32+ import kotlin.reflect.KClass
3033
3134internal open class StringResolver {
35+ // Avoid recomputing the same error message for each type of exception
36+ private val cachedErrorMessages = mutableMapOf<KClass <out AuthException >, String > ()
37+
3238 @Composable
3339 @ReadOnlyComposable
3440 open fun label (config : FieldConfig ): String {
@@ -41,54 +47,49 @@ internal open class StringResolver {
4147
4248 @Composable
4349 @ReadOnlyComposable
44- private fun title (config : FieldConfig ): String {
45- return config.label ? : when (config.key) {
46- FieldKey .ConfirmPassword -> stringResource(R .string.amplify_ui_authenticator_field_label_password_confirm)
47- FieldKey .ConfirmationCode -> stringResource(R .string.amplify_ui_authenticator_field_label_confirmation_code)
48- FieldKey .Password -> stringResource(R .string.amplify_ui_authenticator_field_label_password)
49- FieldKey .PhoneNumber -> stringResource(R .string.amplify_ui_authenticator_field_label_phone_number)
50- FieldKey .Email -> stringResource(R .string.amplify_ui_authenticator_field_label_email)
51- FieldKey .Username -> stringResource(R .string.amplify_ui_authenticator_field_label_username)
52- FieldKey .Birthdate -> stringResource(R .string.amplify_ui_authenticator_field_label_birthdate)
53- FieldKey .FamilyName -> stringResource(R .string.amplify_ui_authenticator_field_label_family_name)
54- FieldKey .GivenName -> stringResource(R .string.amplify_ui_authenticator_field_label_given_name)
55- FieldKey .MiddleName -> stringResource(R .string.amplify_ui_authenticator_field_label_middle_name)
56- FieldKey .Name -> stringResource(R .string.amplify_ui_authenticator_field_label_name)
57- FieldKey .Website -> stringResource(R .string.amplify_ui_authenticator_field_label_website)
58- FieldKey .PhoneNumber -> stringResource(R .string.amplify_ui_authenticator_field_label_phone_number)
59- FieldKey .Nickname -> stringResource(R .string.amplify_ui_authenticator_field_label_nickname)
60- FieldKey .PreferredUsername ->
61- stringResource(R .string.amplify_ui_authenticator_field_label_preferred_username)
62- FieldKey .Profile -> stringResource(R .string.amplify_ui_authenticator_field_label_profile)
63- FieldKey .VerificationAttribute ->
64- stringResource(R .string.amplify_ui_authenticator_field_label_verification_attribute)
65- else -> " "
66- }
50+ private fun title (config : FieldConfig ): String = config.label ? : when (config.key) {
51+ FieldKey .ConfirmPassword -> stringResource(R .string.amplify_ui_authenticator_field_label_password_confirm)
52+ FieldKey .ConfirmationCode -> stringResource(R .string.amplify_ui_authenticator_field_label_confirmation_code)
53+ FieldKey .Password -> stringResource(R .string.amplify_ui_authenticator_field_label_password)
54+ FieldKey .PhoneNumber -> stringResource(R .string.amplify_ui_authenticator_field_label_phone_number)
55+ FieldKey .Email -> stringResource(R .string.amplify_ui_authenticator_field_label_email)
56+ FieldKey .Username -> stringResource(R .string.amplify_ui_authenticator_field_label_username)
57+ FieldKey .Birthdate -> stringResource(R .string.amplify_ui_authenticator_field_label_birthdate)
58+ FieldKey .FamilyName -> stringResource(R .string.amplify_ui_authenticator_field_label_family_name)
59+ FieldKey .GivenName -> stringResource(R .string.amplify_ui_authenticator_field_label_given_name)
60+ FieldKey .MiddleName -> stringResource(R .string.amplify_ui_authenticator_field_label_middle_name)
61+ FieldKey .Name -> stringResource(R .string.amplify_ui_authenticator_field_label_name)
62+ FieldKey .Website -> stringResource(R .string.amplify_ui_authenticator_field_label_website)
63+ FieldKey .PhoneNumber -> stringResource(R .string.amplify_ui_authenticator_field_label_phone_number)
64+ FieldKey .Nickname -> stringResource(R .string.amplify_ui_authenticator_field_label_nickname)
65+ FieldKey .PreferredUsername ->
66+ stringResource(R .string.amplify_ui_authenticator_field_label_preferred_username)
67+ FieldKey .Profile -> stringResource(R .string.amplify_ui_authenticator_field_label_profile)
68+ FieldKey .VerificationAttribute ->
69+ stringResource(R .string.amplify_ui_authenticator_field_label_verification_attribute)
70+ else -> " "
6771 }
6872
6973 @Composable
7074 @ReadOnlyComposable
71- open fun hint (config : FieldConfig ): String? {
72- return config.hint ? : when {
73- config.key == FieldKey .ConfirmPassword ->
74- stringResource(R .string.amplify_ui_authenticator_field_hint_password_confirm)
75- config is FieldConfig .Date -> " yyyy-mm-dd"
76- else -> {
77- val label = label(config)
78- stringResource(R .string.amplify_ui_authenticator_field_hint, label)
79- }
75+ open fun hint (config : FieldConfig ): String? = config.hint ? : when {
76+ config.key == FieldKey .ConfirmPassword ->
77+ stringResource(R .string.amplify_ui_authenticator_field_hint_password_confirm)
78+ config is FieldConfig .Date -> " yyyy-mm-dd"
79+ else -> {
80+ val label = label(config)
81+ stringResource(R .string.amplify_ui_authenticator_field_hint, label)
8082 }
8183 }
8284
83- @OptIn(ExperimentalComposeUiApi ::class )
8485 @Composable
8586 @ReadOnlyComposable
86- open fun error (config : FieldConfig , error : FieldError ): String {
87- return when (error) {
88- is FieldError . InvalidPassword -> {
89- var errorText = stringResource( R .string.amplify_ui_authenticator_field_password_requirements)
90- error.errors.forEach {
91- errorText + = " \n " + when (it) {
87+ open fun error (config : FieldConfig , error : FieldError ): String = when (error) {
88+ is FieldError . InvalidPassword -> {
89+ var errorText = stringResource( R .string.amplify_ui_authenticator_field_password_requirements)
90+ error.errors.forEach {
91+ errorText + = " \n " +
92+ when (it) {
9293 is PasswordError .InvalidPasswordLength ->
9394 pluralStringResource(
9495 id = R .plurals.amplify_ui_authenticator_field_password_too_short,
@@ -105,54 +106,57 @@ internal open class StringResolver {
105106 stringResource(R .string.amplify_ui_authenticator_field_password_missing_lower)
106107 else -> " "
107108 }
108- }
109- errorText
110- }
111- FieldError .PasswordsDoNotMatch ->
112- stringResource(R .string.amplify_ui_authenticator_field_warn_unmatched_password)
113- FieldError .MissingRequired -> {
114- val label = title(config)
115- stringResource(R .string.amplify_ui_authenticator_field_warn_empty, label)
116- }
117- FieldError .InvalidFormat -> {
118- val label = title(config)
119- stringResource(R .string.amplify_ui_authenticator_field_warn_invalid_format, label)
120- }
121- FieldError .FieldValueExists -> {
122- val label = title(config)
123- stringResource(R .string.amplify_ui_authenticator_field_warn_existing, label)
124- }
125- FieldError .ConfirmationCodeIncorrect -> {
126- stringResource(R .string.amplify_ui_authenticator_field_warn_incorrect_code)
127109 }
128- is FieldError .Custom -> error.message
129- FieldError .NotFound -> {
130- val label = title(config)
131- stringResource(R .string.amplify_ui_authenticator_field_warn_not_found, label)
132- }
133- else -> " "
110+ errorText
111+ }
112+ FieldError .PasswordsDoNotMatch ->
113+ stringResource(R .string.amplify_ui_authenticator_field_warn_unmatched_password)
114+ FieldError .MissingRequired -> {
115+ val label = title(config)
116+ stringResource(R .string.amplify_ui_authenticator_field_warn_empty, label)
117+ }
118+ FieldError .InvalidFormat -> {
119+ val label = title(config)
120+ stringResource(R .string.amplify_ui_authenticator_field_warn_invalid_format, label)
121+ }
122+ FieldError .FieldValueExists -> {
123+ val label = title(config)
124+ stringResource(R .string.amplify_ui_authenticator_field_warn_existing, label)
125+ }
126+ FieldError .ConfirmationCodeIncorrect -> {
127+ stringResource(R .string.amplify_ui_authenticator_field_warn_incorrect_code)
128+ }
129+ is FieldError .Custom -> error.message
130+ FieldError .NotFound -> {
131+ val label = title(config)
132+ stringResource(R .string.amplify_ui_authenticator_field_warn_not_found, label)
134133 }
134+ else -> " "
135135 }
136136
137- @Suppress( " UNUSED_EXPRESSION " )
137+ @SuppressLint( " DiscouragedApi " )
138138 @Composable
139139 @ReadOnlyComposable
140140 open fun error (error : AuthException ): String {
141- return when (error) {
142- else -> stringResource(R .string.amplify_ui_authenticator_error_unknown)
141+ val context = LocalContext .current
142+ return cachedErrorMessages.getOrPut(error::class ) {
143+ // Check if the customer application has defined a specific string for this Exception type. If not, return
144+ // the generic error message.
145+ val resourceName = error.toResourceName()
146+ val resourceId = context.resources.getIdentifier(resourceName, " string" , context.packageName)
147+ val message = if (resourceId != 0 ) stringResource(resourceId) else null
148+ message ? : stringResource(R .string.amplify_ui_authenticator_error_unknown)
143149 }
144150 }
145151
146152 companion object {
147153 @Composable
148154 @ReadOnlyComposable
149- fun label (config : FieldConfig ) =
150- LocalStringResolver .current.label(config = config)
155+ fun label (config : FieldConfig ) = LocalStringResolver .current.label(config = config)
151156
152157 @Composable
153158 @ReadOnlyComposable
154- fun hint (config : FieldConfig ) =
155- LocalStringResolver .current.hint(config = config)
159+ fun hint (config : FieldConfig ) = LocalStringResolver .current.hint(config = config)
156160
157161 @Composable
158162 @ReadOnlyComposable
@@ -161,7 +165,6 @@ internal open class StringResolver {
161165
162166 @Composable
163167 @ReadOnlyComposable
164- fun error (error : AuthException ) =
165- LocalStringResolver .current.error(error = error)
168+ fun error (error : AuthException ) = LocalStringResolver .current.error(error = error)
166169 }
167170}
0 commit comments