|
14 | 14 | * limitations under the License. |
15 | 15 | */ |
16 | 16 |
|
17 | | -package com.duckduckgo.autofill.ui.credential.management |
| 17 | +package com.duckduckgo.autofill.ui.credential.management.sorting |
18 | 18 |
|
19 | 19 | import com.duckduckgo.autofill.AutofillDomainFormatter |
20 | 20 | import com.duckduckgo.autofill.domain.app.LoginCredentials |
21 | 21 | import com.duckduckgo.di.scopes.FragmentScope |
22 | 22 | import com.squareup.anvil.annotations.ContributesBinding |
| 23 | +import timber.log.Timber |
| 24 | +import java.lang.Character.* |
| 25 | +import java.text.Normalizer |
23 | 26 | import javax.inject.Inject |
24 | 27 |
|
25 | 28 | interface InitialExtractor { |
26 | | - fun extractInitial(loginCredentials: LoginCredentials): Char |
27 | | - fun extractInitialFromTitle(loginCredentials: LoginCredentials): Char? |
28 | | - fun extractInitialFromDomain(loginCredentials: LoginCredentials): Char? |
| 29 | + fun extractInitial(loginCredentials: LoginCredentials): String |
| 30 | + fun extractInitialFromTitle(loginCredentials: LoginCredentials): String? |
| 31 | + fun extractInitialFromDomain(loginCredentials: LoginCredentials): String? |
29 | 32 | } |
30 | 33 |
|
31 | 34 | @ContributesBinding(FragmentScope::class) |
32 | 35 | class CredentialInitialExtractor @Inject constructor( |
33 | | - private val domainFormatter: AutofillDomainFormatter, |
34 | | - private val characterValidator: AutofillCharacterValidator |
| 36 | + private val domainFormatter: AutofillDomainFormatter |
35 | 37 | ) : InitialExtractor { |
36 | 38 |
|
37 | | - override fun extractInitial(loginCredentials: LoginCredentials): Char { |
38 | | - val initial = extractInitialFromTitle(loginCredentials) ?: extractInitialFromDomain(loginCredentials) |
| 39 | + override fun extractInitial(loginCredentials: LoginCredentials): String { |
| 40 | + val rawInitial = |
| 41 | + extractInitialFromTitle(loginCredentials) ?: extractInitialFromDomain(loginCredentials) ?: return INITIAL_CHAR_FOR_NON_LETTERS |
39 | 42 |
|
40 | | - if (initial == null || !characterValidator.isLetter(initial)) { |
41 | | - return INITIAL_CHAR_FOR_NON_LETTERS |
| 43 | + return when (val type = getCharacterType(rawInitial)) { |
| 44 | + LOWERCASE_LETTER, |
| 45 | + UPPERCASE_LETTER, |
| 46 | + OTHER_LETTER, |
| 47 | + DECIMAL_DIGIT_NUMBER |
| 48 | + -> { |
| 49 | + Normalizer.normalize(rawInitial, Normalizer.Form.NFKD).firstOrNull()?.toString() ?: INITIAL_CHAR_FOR_NON_LETTERS |
| 50 | + } |
| 51 | + else -> { |
| 52 | + Timber.v("Rejecting type %d for %s", type, rawInitial) |
| 53 | + INITIAL_CHAR_FOR_NON_LETTERS |
| 54 | + } |
42 | 55 | } |
| 56 | + } |
43 | 57 |
|
44 | | - return initial.uppercaseChar() |
| 58 | + private fun getCharacterType(rawInitial: String): Byte { |
| 59 | + val initial = rawInitial.firstOrNull() ?: return UNASSIGNED |
| 60 | + return getType(initial).toByte() |
45 | 61 | } |
46 | 62 |
|
47 | | - override fun extractInitialFromTitle(loginCredentials: LoginCredentials): Char? { |
48 | | - return loginCredentials.domainTitle?.firstOrNull()?.uppercaseChar() |
| 63 | + override fun extractInitialFromTitle(loginCredentials: LoginCredentials): String? { |
| 64 | + return loginCredentials.domainTitle?.firstOrNull()?.uppercaseChar()?.toString() |
49 | 65 | } |
50 | 66 |
|
51 | | - override fun extractInitialFromDomain(loginCredentials: LoginCredentials): Char? { |
52 | | - return domainFormatter.extractDomain(loginCredentials.domain)?.firstOrNull()?.uppercaseChar() |
| 67 | + override fun extractInitialFromDomain(loginCredentials: LoginCredentials): String? { |
| 68 | + return domainFormatter.extractDomain(loginCredentials.domain)?.firstOrNull()?.uppercaseChar()?.toString() |
53 | 69 | } |
54 | 70 |
|
55 | 71 | companion object { |
56 | | - const val INITIAL_CHAR_FOR_NON_LETTERS = '#' |
| 72 | + const val INITIAL_CHAR_FOR_NON_LETTERS = "#" |
57 | 73 | } |
58 | 74 | } |
0 commit comments