Skip to content

Commit f0558c4

Browse files
committed
add repeat 1
1 parent 9d2de66 commit f0558c4

File tree

16 files changed

+352
-18
lines changed

16 files changed

+352
-18
lines changed

app/src/test/java/com/duckduckgo/app/dispatchers/AutofillEffectDispatcherViewModelTest.kt renamed to app/src/test/java/com/duckduckgo/app/dispatchers/IntentDispatcherViewModelTest.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ import org.mockito.kotlin.anyOrNull
3838
import org.mockito.kotlin.mock
3939
import org.mockito.kotlin.whenever
4040

41-
class AutofillEffectDispatcherViewModelTest {
41+
class IntentDispatcherViewModelTest {
4242
@get:Rule
4343
val coroutineTestRule: CoroutineTestRule = CoroutineTestRule()
4444

autofill/autofill-api/src/main/java/com/duckduckgo/autofill/api/AutofillFeature.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,6 @@ interface AutofillFeature {
152152
@Toggle.DefaultValue(defaultValue = DefaultFeatureValue.TRUE)
153153
fun createAsyncPreferences(): Toggle
154154

155-
@Toggle.DefaultValue(defaultValue = DefaultFeatureValue.TRUE)
155+
@Toggle.DefaultValue(defaultValue = DefaultFeatureValue.INTERNAL)
156156
fun canPromoteImportPasswords(): Toggle
157157
}

autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/SecureStoreBackedAutofillStore.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,10 @@ class SecureStoreBackedAutofillStore @Inject constructor(
9090
autofillPrefsStore.hasEverImportedPasswords = value
9191
}
9292

93+
override fun hasEverImportedPasswordsFlow(): Flow<Boolean> {
94+
return autofillPrefsStore.hasEverImportedPasswordsFlow()
95+
}
96+
9397
override var hasDismissedImportedPasswordsPromo: Boolean
9498
get() = autofillPrefsStore.hasDismissedImportedPasswordsPromo
9599
set(value) {

autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/CredentialImporter.kt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,12 @@ class CredentialImporterImpl @Inject constructor(
8585
val insertedIds = autofillStore.bulkInsert(importList)
8686

8787
skippedCredentials += (importList.size - insertedIds.size)
88+
89+
// Set the flag when at least one credential was successfully imported
90+
if (insertedIds.isNotEmpty()) {
91+
autofillStore.hasEverImportedPasswords = true
92+
}
93+
8894
_importStatus.emit(Finished(savedCredentials = insertedIds.size, numberSkipped = skippedCredentials))
8995
}
9096

autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/promo/ImportInPasswordsPromotion.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ class ImportInPasswordsPromotionView @JvmOverloads constructor(
129129
),
130130
)
131131
onTopAnimationConfigured { view ->
132-
view.repeatCount = 2
132+
view.repeatCount = 1
133133
view.playAnimation()
134134
}
135135
onPrimaryActionClicked {

autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/promo/ImportInPasswordsPromotionViewModel.kt

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@ import com.duckduckgo.autofill.impl.pixel.AutofillPixelNames
2626
import com.duckduckgo.autofill.impl.pixel.AutofillPixelNames.AUTOFILL_IMPORT_GOOGLE_PASSWORDS_EMPTY_STATE_CTA_BUTTON_TAPPED
2727
import com.duckduckgo.autofill.impl.store.AutofillEffect
2828
import com.duckduckgo.autofill.impl.store.AutofillEffectDispatcher
29-
import com.duckduckgo.autofill.impl.store.InternalAutofillStore
3029
import com.duckduckgo.common.utils.DispatcherProvider
3130
import com.duckduckgo.di.scopes.ViewScope
3231
import javax.inject.Inject
@@ -40,8 +39,8 @@ import kotlinx.coroutines.launch
4039
class ImportInPasswordsPromotionViewModel @Inject constructor(
4140
private val pixel: Pixel,
4241
private val dispatchers: DispatcherProvider,
43-
private val internalAutofillStore: InternalAutofillStore,
4442
private val promoEventDispatcher: AutofillEffectDispatcher,
43+
private val importInPasswordsVisibility: ImportInPasswordsVisibility,
4544
) : ViewModel() {
4645

4746
sealed interface Command {
@@ -76,7 +75,7 @@ class ImportInPasswordsPromotionViewModel @Inject constructor(
7675

7776
fun onUserDismissedPromo() {
7877
viewModelScope.launch(dispatchers.io()) {
79-
internalAutofillStore.hasDismissedImportedPasswordsPromo = true
78+
importInPasswordsVisibility.onPromoDismissed()
8079
command.send(DismissImport)
8180
}
8281
}

autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/importing/promo/ImportInPasswordsVisibility.kt

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,20 @@ import com.duckduckgo.autofill.impl.store.InternalAutofillStore
2525
import com.duckduckgo.common.utils.DispatcherProvider
2626
import com.duckduckgo.di.scopes.AppScope
2727
import com.squareup.anvil.annotations.ContributesBinding
28+
import dagger.SingleInstanceIn
2829
import javax.inject.Inject
2930
import kotlinx.coroutines.CoroutineScope
31+
import kotlinx.coroutines.flow.collect
3032
import kotlinx.coroutines.launch
3133
import logcat.logcat
3234

3335
interface ImportInPasswordsVisibility {
3436
fun canShowImportInPasswords(numberSavedPasswords: Int): Boolean
37+
fun onPromoDismissed()
3538
}
3639

3740
@ContributesBinding(AppScope::class)
41+
@SingleInstanceIn(AppScope::class)
3842
class RealImportInPasswordsVisibility @Inject constructor(
3943
private val internalAutofillStore: InternalAutofillStore,
4044
private val autofillFeature: AutofillFeature,
@@ -50,6 +54,17 @@ class RealImportInPasswordsVisibility @Inject constructor(
5054
logcat { "Autofill: Evaluating if user can show import promo" }
5155
canShowImportPasswords = evaluateIfUserCanShowImportPromo()
5256
logcat { "Autofill: Evaluation result, can show import promo? $canShowImportPasswords" }
57+
58+
if (!canShowImportPasswords) return@launch
59+
60+
// Observe changes of hasEverImportedPasswordsFlow only if the promo can be shown
61+
internalAutofillStore.hasEverImportedPasswordsFlow().collect { hasImported ->
62+
logcat { "Autofill: hasEverImportedPasswords changed to $hasImported" }
63+
if (hasImported) {
64+
canShowImportPasswords = false
65+
logcat { "Autofill: User has imported passwords, hiding promo" }
66+
}
67+
}
5368
}
5469
}
5570

@@ -58,6 +73,11 @@ class RealImportInPasswordsVisibility @Inject constructor(
5873
return canShowImportPasswords
5974
}
6075

76+
override fun onPromoDismissed() {
77+
internalAutofillStore.hasDismissedImportedPasswordsPromo = true
78+
canShowImportPasswords = false
79+
}
80+
6181
private suspend fun evaluateIfUserCanShowImportPromo(): Boolean {
6282
if (autofillFeature.canPromoteImportPasswords().isEnabled().not()) return false
6383

autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/impl/store/InternalAutofillStore.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ interface InternalAutofillStore : AutofillStore {
4242

4343
var hasEverImportedPasswords: Boolean
4444

45+
fun hasEverImportedPasswordsFlow(): Flow<Boolean>
46+
4547
var hasDismissedImportedPasswordsPromo: Boolean
4648

4749
/**

autofill/autofill-impl/src/main/java/com/duckduckgo/autofill/store/AutofillPrefsStore.kt

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ import android.content.Context
2121
import android.content.SharedPreferences
2222
import androidx.core.content.edit
2323
import com.duckduckgo.autofill.store.feature.AutofillDefaultStateDecider
24+
import kotlinx.coroutines.flow.Flow
25+
import kotlinx.coroutines.flow.MutableSharedFlow
26+
import kotlinx.coroutines.flow.distinctUntilChanged
27+
import kotlinx.coroutines.flow.onStart
2428
import logcat.LogPriority.INFO
2529
import logcat.logcat
2630

@@ -30,6 +34,7 @@ interface AutofillPrefsStore {
3034
var monitorDeclineCounts: Boolean
3135
var hasEverBeenPromptedToSaveLogin: Boolean
3236
var hasEverImportedPasswords: Boolean
37+
fun hasEverImportedPasswordsFlow(): Flow<Boolean>
3338
var hasDismissedImportedPasswordsPromo: Boolean
3439
val autofillStateSetByUser: Boolean
3540
var timestampUserLastPromptedToDisableAutofill: Long?
@@ -60,6 +65,8 @@ class RealAutofillPrefsStore(
6065
applicationContext.getSharedPreferences(FILENAME, Context.MODE_PRIVATE)
6166
}
6267

68+
private val hasEverImportedPasswordsFlow = MutableSharedFlow<Boolean>(replay = 1)
69+
6370
override var isEnabled: Boolean
6471
get(): Boolean {
6572
// if autofill state has been manually set by user, honor that
@@ -87,7 +94,16 @@ class RealAutofillPrefsStore(
8794

8895
override var hasEverImportedPasswords: Boolean
8996
get() = prefs.getBoolean(HAS_EVER_IMPORT_PASSWORDS, false)
90-
set(value) = prefs.edit { putBoolean(HAS_EVER_IMPORT_PASSWORDS, value) }
97+
set(value) {
98+
prefs.edit { putBoolean(HAS_EVER_IMPORT_PASSWORDS, value) }
99+
hasEverImportedPasswordsFlow.tryEmit(value)
100+
}
101+
102+
override fun hasEverImportedPasswordsFlow(): Flow<Boolean> {
103+
return hasEverImportedPasswordsFlow
104+
.onStart { emit(hasEverImportedPasswords) }
105+
.distinctUntilChanged()
106+
}
91107

92108
override var hasDismissedImportedPasswordsPromo: Boolean
93109
get() = prefs.getBoolean(HAS_DISMISSED_IMPORT_PASSWORDS_PROMO, false)

autofill/autofill-impl/src/test/java/com/duckduckgo/autofill/impl/importing/CredentialImporterImplTest.kt

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,23 +6,25 @@ import com.duckduckgo.autofill.impl.importing.CredentialImporter.ImportResult
66
import com.duckduckgo.autofill.impl.store.InternalAutofillStore
77
import com.duckduckgo.common.test.CoroutineTestRule
88
import kotlinx.coroutines.CoroutineScope
9-
import kotlinx.coroutines.test.StandardTestDispatcher
10-
import kotlinx.coroutines.test.TestCoroutineScheduler
119
import kotlinx.coroutines.test.runTest
1210
import org.junit.Assert.*
1311
import org.junit.Before
1412
import org.junit.Rule
1513
import org.junit.Test
1614
import org.mockito.kotlin.any
1715
import org.mockito.kotlin.mock
16+
import org.mockito.kotlin.never
17+
import org.mockito.kotlin.verify
1818
import org.mockito.kotlin.whenever
1919

2020
class CredentialImporterImplTest {
21+
2122
@get:Rule
22-
val coroutineTestRule: CoroutineTestRule = CoroutineTestRule(StandardTestDispatcher(TestCoroutineScheduler()))
23+
var coroutinesTestRule = CoroutineTestRule()
24+
2325
private val autofillStore: InternalAutofillStore = mock()
24-
private val dispatchers = coroutineTestRule.testDispatcherProvider
25-
private val appCoroutineScope: CoroutineScope = coroutineTestRule.testScope
26+
private val dispatchers = coroutinesTestRule.testDispatcherProvider
27+
private val appCoroutineScope: CoroutineScope = coroutinesTestRule.testScope
2628

2729
private val credentialsAlreadyInDb = mutableListOf<LoginCredentials>()
2830

@@ -110,6 +112,26 @@ class CredentialImporterImplTest {
110112
assertResult(numberSkippedExpected = 2, importListSizeExpected = 1)
111113
}
112114

115+
@Test
116+
fun whenImportingCredentialsSuccessfullyThenHasEverImportedPasswordsIsSetToTrue() = runTest {
117+
listOf(creds()).import()
118+
verify(autofillStore).hasEverImportedPasswords = true
119+
}
120+
121+
@Test
122+
fun whenImportingNoCredentialsThenHasEverImportedPasswordsIsNotSet() = runTest {
123+
listOf<LoginCredentials>().import()
124+
verify(autofillStore, never()).hasEverImportedPasswords = true
125+
}
126+
127+
@Test
128+
fun whenImportingOnlyDuplicatesThenHasEverImportedPasswordsIsNotSet() = runTest {
129+
val duplicatedLogin = creds(username = "username")
130+
duplicatedLogin.treatAsDuplicate()
131+
listOf(duplicatedLogin).import()
132+
verify(autofillStore, never()).hasEverImportedPasswords = true
133+
}
134+
113135
private suspend fun List<LoginCredentials>.import(originalListSize: Int = this.size) {
114136
testee.import(this, originalListSize)
115137
}
@@ -119,7 +141,6 @@ class CredentialImporterImplTest {
119141
importListSizeExpected: Int,
120142
) {
121143
testee.getImportStatus().test {
122-
awaitItem()
123144
with(awaitItem() as ImportResult.Finished) {
124145
assertEquals("Wrong number of duplicates in result", numberSkippedExpected, numberSkipped)
125146
assertEquals("Wrong import size in result", importListSizeExpected, savedCredentials)

0 commit comments

Comments
 (0)