mirror of
https://github.com/bitwarden/android.git
synced 2025-02-17 04:19:54 +03:00
Navigate to the Vault Listing screen from autofill (#810)
This commit is contained in:
parent
0411ccd3f9
commit
f2a7998bb0
16 changed files with 374 additions and 27 deletions
|
@ -4,6 +4,7 @@ import android.content.Intent
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
|
import com.x8bit.bitwarden.data.autofill.util.getAutofillSelectionDataOrNull
|
||||||
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
||||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||||
|
@ -91,8 +92,19 @@ class MainViewModel @Inject constructor(
|
||||||
intent: Intent,
|
intent: Intent,
|
||||||
isFirstIntent: Boolean,
|
isFirstIntent: Boolean,
|
||||||
) {
|
) {
|
||||||
|
val autofillSelectionData = intent.getAutofillSelectionDataOrNull()
|
||||||
val shareData = intentManager.getShareDataFromIntent(intent)
|
val shareData = intentManager.getShareDataFromIntent(intent)
|
||||||
when {
|
when {
|
||||||
|
autofillSelectionData != null -> {
|
||||||
|
specialCircumstanceManager.specialCircumstance =
|
||||||
|
SpecialCircumstance.AutofillSelection(
|
||||||
|
autofillSelectionData = autofillSelectionData,
|
||||||
|
// Allow users back into the already-running app when completing the
|
||||||
|
// autofill task when this is not the first intent.
|
||||||
|
shouldFinishWhenComplete = isFirstIntent,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
shareData != null -> {
|
shareData != null -> {
|
||||||
specialCircumstanceManager.specialCircumstance =
|
specialCircumstanceManager.specialCircumstance =
|
||||||
SpecialCircumstance.ShareNewSend(
|
SpecialCircumstance.ShareNewSend(
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package com.x8bit.bitwarden.data.autofill.model
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents data for a manual autofill selection.
|
||||||
|
*
|
||||||
|
* @property type The type of autofill selection that must be made.
|
||||||
|
* @property uri A URI representing the location where data should be filled (if available).
|
||||||
|
*/
|
||||||
|
@Parcelize
|
||||||
|
class AutofillSelectionData(
|
||||||
|
val type: Type,
|
||||||
|
val uri: String?,
|
||||||
|
) : Parcelable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The type of selection the user must make.
|
||||||
|
*/
|
||||||
|
enum class Type {
|
||||||
|
CARD,
|
||||||
|
LOGIN,
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
@file:OmitFromCoverage
|
||||||
|
|
||||||
|
package com.x8bit.bitwarden.data.autofill.util
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.content.Intent
|
||||||
|
import android.os.Build
|
||||||
|
import com.x8bit.bitwarden.MainActivity
|
||||||
|
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
||||||
|
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||||
|
|
||||||
|
private const val AUTOFILL_SELECTION_DATA_KEY = "autofill-selection-data"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an [Intent] in order to send the user to a manual selection process for autofill.
|
||||||
|
*/
|
||||||
|
fun createAutofillSelectionIntent(
|
||||||
|
context: Context,
|
||||||
|
type: AutofillSelectionData.Type,
|
||||||
|
uri: String?,
|
||||||
|
): Intent =
|
||||||
|
Intent(
|
||||||
|
context,
|
||||||
|
MainActivity::class.java,
|
||||||
|
)
|
||||||
|
.apply {
|
||||||
|
putExtra(
|
||||||
|
AUTOFILL_SELECTION_DATA_KEY,
|
||||||
|
AutofillSelectionData(
|
||||||
|
type = type,
|
||||||
|
uri = uri,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if the given [Intent] contains data about an ongoing manual autofill selection process.
|
||||||
|
* The [AutofillSelectionData] will be returned when present.
|
||||||
|
*/
|
||||||
|
fun Intent.getAutofillSelectionDataOrNull(): AutofillSelectionData? {
|
||||||
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||||
|
this.getParcelableExtra(AUTOFILL_SELECTION_DATA_KEY, AutofillSelectionData::class.java)
|
||||||
|
} else {
|
||||||
|
this.getParcelableExtra(AUTOFILL_SELECTION_DATA_KEY)
|
||||||
|
}
|
||||||
|
}
|
|
@ -2,7 +2,6 @@ package com.x8bit.bitwarden.data.autofill.util
|
||||||
|
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.app.PendingIntent
|
import android.app.PendingIntent
|
||||||
import android.content.Intent
|
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.service.autofill.Dataset
|
import android.service.autofill.Dataset
|
||||||
import android.service.autofill.Presentations
|
import android.service.autofill.Presentations
|
||||||
|
@ -11,8 +10,9 @@ import android.view.autofill.AutofillValue
|
||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
import android.widget.inline.InlinePresentationSpec
|
import android.widget.inline.InlinePresentationSpec
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import com.x8bit.bitwarden.MainActivity
|
|
||||||
import com.x8bit.bitwarden.data.autofill.model.AutofillAppInfo
|
import com.x8bit.bitwarden.data.autofill.model.AutofillAppInfo
|
||||||
|
import com.x8bit.bitwarden.data.autofill.model.AutofillPartition
|
||||||
|
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
||||||
import com.x8bit.bitwarden.data.autofill.model.FilledData
|
import com.x8bit.bitwarden.data.autofill.model.FilledData
|
||||||
import com.x8bit.bitwarden.data.autofill.model.FilledItem
|
import com.x8bit.bitwarden.data.autofill.model.FilledItem
|
||||||
import com.x8bit.bitwarden.ui.autofill.buildVaultItemAutofillRemoteViews
|
import com.x8bit.bitwarden.ui.autofill.buildVaultItemAutofillRemoteViews
|
||||||
|
@ -31,11 +31,14 @@ val FilledData.fillableAutofillIds: List<AutofillId>
|
||||||
fun FilledData.buildVaultItemDataset(
|
fun FilledData.buildVaultItemDataset(
|
||||||
autofillAppInfo: AutofillAppInfo,
|
autofillAppInfo: AutofillAppInfo,
|
||||||
): Dataset {
|
): Dataset {
|
||||||
val intent = Intent(
|
val intent = createAutofillSelectionIntent(
|
||||||
autofillAppInfo.context,
|
context = autofillAppInfo.context,
|
||||||
MainActivity::class.java,
|
type = when (this.originalPartition) {
|
||||||
|
is AutofillPartition.Card -> AutofillSelectionData.Type.CARD
|
||||||
|
is AutofillPartition.Login -> AutofillSelectionData.Type.LOGIN
|
||||||
|
},
|
||||||
|
uri = this.uri,
|
||||||
)
|
)
|
||||||
// TODO: Add additional data to the Intent to be pulled out in the app (BIT-1296)
|
|
||||||
|
|
||||||
val pendingIntent = PendingIntent
|
val pendingIntent = PendingIntent
|
||||||
.getActivity(
|
.getActivity(
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.x8bit.bitwarden.data.platform.manager.model
|
package com.x8bit.bitwarden.data.platform.manager.model
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
|
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
||||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
@ -17,4 +18,13 @@ sealed class SpecialCircumstance : Parcelable {
|
||||||
val data: IntentManager.ShareData,
|
val data: IntentManager.ShareData,
|
||||||
val shouldFinishWhenComplete: Boolean,
|
val shouldFinishWhenComplete: Boolean,
|
||||||
) : SpecialCircumstance()
|
) : SpecialCircumstance()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The app was launched in order to allow the user to manually select data for autofill.
|
||||||
|
*/
|
||||||
|
@Parcelize
|
||||||
|
data class AutofillSelection(
|
||||||
|
val autofillSelectionData: AutofillSelectionData,
|
||||||
|
val shouldFinishWhenComplete: Boolean,
|
||||||
|
) : SpecialCircumstance()
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ import com.x8bit.bitwarden.ui.auth.feature.auth.navigateToAuthGraph
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.vaultunlock.VAULT_UNLOCK_ROUTE
|
import com.x8bit.bitwarden.ui.auth.feature.vaultunlock.VAULT_UNLOCK_ROUTE
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.vaultunlock.navigateToVaultUnlock
|
import com.x8bit.bitwarden.ui.auth.feature.vaultunlock.navigateToVaultUnlock
|
||||||
import com.x8bit.bitwarden.ui.auth.feature.vaultunlock.vaultUnlockDestination
|
import com.x8bit.bitwarden.ui.auth.feature.vaultunlock.vaultUnlockDestination
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.rootnav.util.toVaultItemListingType
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.splash.SPLASH_ROUTE
|
import com.x8bit.bitwarden.ui.platform.feature.splash.SPLASH_ROUTE
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.splash.navigateToSplash
|
import com.x8bit.bitwarden.ui.platform.feature.splash.navigateToSplash
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.splash.splashDestination
|
import com.x8bit.bitwarden.ui.platform.feature.splash.splashDestination
|
||||||
|
@ -26,6 +27,7 @@ import com.x8bit.bitwarden.ui.platform.feature.vaultunlocked.vaultUnlockedGraph
|
||||||
import com.x8bit.bitwarden.ui.platform.theme.RootTransitionProviders
|
import com.x8bit.bitwarden.ui.platform.theme.RootTransitionProviders
|
||||||
import com.x8bit.bitwarden.ui.tools.feature.send.addsend.model.AddSendType
|
import com.x8bit.bitwarden.ui.tools.feature.send.addsend.model.AddSendType
|
||||||
import com.x8bit.bitwarden.ui.tools.feature.send.addsend.navigateToAddSend
|
import com.x8bit.bitwarden.ui.tools.feature.send.addsend.navigateToAddSend
|
||||||
|
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.navigateToVaultItemListingAsRoot
|
||||||
import kotlinx.coroutines.flow.launchIn
|
import kotlinx.coroutines.flow.launchIn
|
||||||
import kotlinx.coroutines.flow.onEach
|
import kotlinx.coroutines.flow.onEach
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
|
@ -76,7 +78,8 @@ fun RootNavScreen(
|
||||||
RootNavState.Splash -> SPLASH_ROUTE
|
RootNavState.Splash -> SPLASH_ROUTE
|
||||||
RootNavState.VaultLocked -> VAULT_UNLOCK_ROUTE
|
RootNavState.VaultLocked -> VAULT_UNLOCK_ROUTE
|
||||||
is RootNavState.VaultUnlocked,
|
is RootNavState.VaultUnlocked,
|
||||||
RootNavState.VaultUnlockedForNewSend,
|
is RootNavState.VaultUnlockedForAutofillSelection,
|
||||||
|
is RootNavState.VaultUnlockedForNewSend,
|
||||||
-> VAULT_UNLOCKED_GRAPH_ROUTE
|
-> VAULT_UNLOCKED_GRAPH_ROUTE
|
||||||
}
|
}
|
||||||
val currentRoute = navController.currentDestination?.rootLevelRoute()
|
val currentRoute = navController.currentDestination?.rootLevelRoute()
|
||||||
|
@ -102,7 +105,7 @@ fun RootNavScreen(
|
||||||
restoreState = false
|
restoreState = false
|
||||||
}
|
}
|
||||||
|
|
||||||
when (state) {
|
when (val currentState = state) {
|
||||||
RootNavState.Auth -> navController.navigateToAuthGraph(rootNavOptions)
|
RootNavState.Auth -> navController.navigateToAuthGraph(rootNavOptions)
|
||||||
RootNavState.Splash -> navController.navigateToSplash(rootNavOptions)
|
RootNavState.Splash -> navController.navigateToSplash(rootNavOptions)
|
||||||
RootNavState.VaultLocked -> navController.navigateToVaultUnlock(rootNavOptions)
|
RootNavState.VaultLocked -> navController.navigateToVaultUnlock(rootNavOptions)
|
||||||
|
@ -114,6 +117,14 @@ fun RootNavScreen(
|
||||||
navOptions = rootNavOptions,
|
navOptions = rootNavOptions,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
is RootNavState.VaultUnlockedForAutofillSelection -> {
|
||||||
|
navController.navigateToVaultUnlockedGraph(rootNavOptions)
|
||||||
|
navController.navigateToVaultItemListingAsRoot(
|
||||||
|
vaultItemListingType = currentState.type.toVaultItemListingType(),
|
||||||
|
navOptions = rootNavOptions,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import android.os.Parcelable
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||||
|
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
||||||
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
||||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||||
|
@ -64,10 +65,15 @@ class RootNavViewModel @Inject constructor(
|
||||||
|
|
||||||
userState.activeAccount.isVaultUnlocked -> {
|
userState.activeAccount.isVaultUnlocked -> {
|
||||||
when (specialCircumstance) {
|
when (specialCircumstance) {
|
||||||
|
is SpecialCircumstance.AutofillSelection -> {
|
||||||
|
RootNavState.VaultUnlockedForAutofillSelection(
|
||||||
|
type = specialCircumstance.autofillSelectionData.type,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
is SpecialCircumstance.ShareNewSend -> RootNavState.VaultUnlockedForNewSend
|
is SpecialCircumstance.ShareNewSend -> RootNavState.VaultUnlockedForNewSend
|
||||||
|
|
||||||
null,
|
null -> {
|
||||||
-> {
|
|
||||||
RootNavState.VaultUnlocked(
|
RootNavState.VaultUnlocked(
|
||||||
activeUserId = userState.activeAccount.userId,
|
activeUserId = userState.activeAccount.userId,
|
||||||
)
|
)
|
||||||
|
@ -111,6 +117,14 @@ sealed class RootNavState : Parcelable {
|
||||||
val activeUserId: String,
|
val activeUserId: String,
|
||||||
) : RootNavState()
|
) : RootNavState()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* App should show a selection screen for autofill for an unlocked user.
|
||||||
|
*/
|
||||||
|
@Parcelize
|
||||||
|
data class VaultUnlockedForAutofillSelection(
|
||||||
|
val type: AutofillSelectionData.Type,
|
||||||
|
) : RootNavState()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* App should show the new send screen for an unlocked user.
|
* App should show the new send screen for an unlocked user.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
package com.x8bit.bitwarden.ui.platform.feature.rootnav.util
|
||||||
|
|
||||||
|
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
||||||
|
import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derives a [VaultItemListingType] from the given [AutofillSelectionData.Type].
|
||||||
|
*/
|
||||||
|
fun AutofillSelectionData.Type.toVaultItemListingType(): VaultItemListingType =
|
||||||
|
when (this) {
|
||||||
|
AutofillSelectionData.Type.CARD -> VaultItemListingType.Card
|
||||||
|
AutofillSelectionData.Type.LOGIN -> VaultItemListingType.Login
|
||||||
|
}
|
|
@ -34,6 +34,7 @@ import com.x8bit.bitwarden.ui.vault.feature.attachments.attachmentDestination
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.attachments.navigateToAttachment
|
import com.x8bit.bitwarden.ui.vault.feature.attachments.navigateToAttachment
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.item.navigateToVaultItem
|
import com.x8bit.bitwarden.ui.vault.feature.item.navigateToVaultItem
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.item.vaultItemDestination
|
import com.x8bit.bitwarden.ui.vault.feature.item.vaultItemDestination
|
||||||
|
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.vaultItemListingDestinationAsRoot
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.manualcodeentry.navigateToManualCodeEntryScreen
|
import com.x8bit.bitwarden.ui.vault.feature.manualcodeentry.navigateToManualCodeEntryScreen
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.manualcodeentry.vaultManualCodeEntryDestination
|
import com.x8bit.bitwarden.ui.vault.feature.manualcodeentry.vaultManualCodeEntryDestination
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.movetoorganization.navigateToVaultMoveToOrganization
|
import com.x8bit.bitwarden.ui.vault.feature.movetoorganization.navigateToVaultMoveToOrganization
|
||||||
|
@ -62,6 +63,17 @@ fun NavGraphBuilder.vaultUnlockedGraph(
|
||||||
startDestination = VAULT_UNLOCKED_NAV_BAR_ROUTE,
|
startDestination = VAULT_UNLOCKED_NAV_BAR_ROUTE,
|
||||||
route = VAULT_UNLOCKED_GRAPH_ROUTE,
|
route = VAULT_UNLOCKED_GRAPH_ROUTE,
|
||||||
) {
|
) {
|
||||||
|
vaultItemListingDestinationAsRoot(
|
||||||
|
onNavigateBack = { navController.popBackStack() },
|
||||||
|
onNavigateToVaultItemScreen = { navController.navigateToVaultItem(vaultItemId = it) },
|
||||||
|
onNavigateToVaultAddItemScreen = {
|
||||||
|
navController.navigateToVaultAddEdit(VaultAddEditType.AddItem)
|
||||||
|
},
|
||||||
|
onNavigateToSearchVault = { navController.navigateToSearch(searchType = it) },
|
||||||
|
onNavigateToVaultEditItemScreen = {
|
||||||
|
navController.navigateToVaultAddEdit(VaultAddEditType.EditItem(it))
|
||||||
|
},
|
||||||
|
)
|
||||||
vaultUnlockedNavBarDestination(
|
vaultUnlockedNavBarDestination(
|
||||||
onNavigateToExportVault = { navController.navigateToExportVault() },
|
onNavigateToExportVault = { navController.navigateToExportVault() },
|
||||||
onNavigateToFolders = { navController.navigateToFolders() },
|
onNavigateToFolders = { navController.navigateToFolders() },
|
||||||
|
|
|
@ -8,6 +8,7 @@ import androidx.navigation.NavType
|
||||||
import androidx.navigation.navArgument
|
import androidx.navigation.navArgument
|
||||||
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.composableWithPushTransitions
|
import com.x8bit.bitwarden.ui.platform.base.util.composableWithPushTransitions
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.util.composableWithStayTransitions
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||||
import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType
|
import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType
|
||||||
|
|
||||||
|
@ -21,11 +22,15 @@ private const val SEND_FILE: String = "send_file"
|
||||||
private const val SEND_TEXT: String = "send_text"
|
private const val SEND_TEXT: String = "send_text"
|
||||||
private const val TRASH: String = "trash"
|
private const val TRASH: String = "trash"
|
||||||
private const val VAULT_ITEM_LISTING_PREFIX: String = "vault_item_listing"
|
private const val VAULT_ITEM_LISTING_PREFIX: String = "vault_item_listing"
|
||||||
|
private const val VAULT_ITEM_LISTING_AS_ROOT_PREFIX: String = "vault_item_listing_as_root"
|
||||||
private const val VAULT_ITEM_LISTING_TYPE: String = "vault_item_listing_type"
|
private const val VAULT_ITEM_LISTING_TYPE: String = "vault_item_listing_type"
|
||||||
private const val ID: String = "id"
|
private const val ID: String = "id"
|
||||||
private const val VAULT_ITEM_LISTING_ROUTE: String =
|
private const val VAULT_ITEM_LISTING_ROUTE: String =
|
||||||
"$VAULT_ITEM_LISTING_PREFIX/{$VAULT_ITEM_LISTING_TYPE}" +
|
"$VAULT_ITEM_LISTING_PREFIX/{$VAULT_ITEM_LISTING_TYPE}" +
|
||||||
"?$ID={$ID}"
|
"?$ID={$ID}"
|
||||||
|
private const val VAULT_ITEM_LISTING_AS_ROOT_ROUTE: String =
|
||||||
|
"$VAULT_ITEM_LISTING_AS_ROOT_PREFIX/{$VAULT_ITEM_LISTING_TYPE}" +
|
||||||
|
"?$ID={$ID}"
|
||||||
private const val SEND_ITEM_LISTING_PREFIX: String = "send_item_listing"
|
private const val SEND_ITEM_LISTING_PREFIX: String = "send_item_listing"
|
||||||
private const val SEND_ITEM_LISTING_ROUTE: String =
|
private const val SEND_ITEM_LISTING_ROUTE: String =
|
||||||
"$SEND_ITEM_LISTING_PREFIX/{$VAULT_ITEM_LISTING_TYPE}" +
|
"$SEND_ITEM_LISTING_PREFIX/{$VAULT_ITEM_LISTING_TYPE}" +
|
||||||
|
@ -70,6 +75,39 @@ fun NavGraphBuilder.vaultItemListingDestination(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the [VaultItemListingScreen] to the nav graph.
|
||||||
|
*/
|
||||||
|
fun NavGraphBuilder.vaultItemListingDestinationAsRoot(
|
||||||
|
onNavigateBack: () -> Unit,
|
||||||
|
onNavigateToVaultItemScreen: (id: String) -> Unit,
|
||||||
|
onNavigateToVaultEditItemScreen: (cipherId: String) -> Unit,
|
||||||
|
onNavigateToVaultAddItemScreen: () -> Unit,
|
||||||
|
onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit,
|
||||||
|
) {
|
||||||
|
composableWithStayTransitions(
|
||||||
|
route = VAULT_ITEM_LISTING_AS_ROOT_ROUTE,
|
||||||
|
arguments = listOf(
|
||||||
|
navArgument(
|
||||||
|
name = VAULT_ITEM_LISTING_TYPE,
|
||||||
|
builder = {
|
||||||
|
type = NavType.StringType
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
VaultItemListingScreen(
|
||||||
|
onNavigateBack = onNavigateBack,
|
||||||
|
onNavigateToVaultItem = onNavigateToVaultItemScreen,
|
||||||
|
onNavigateToVaultEditItemScreen = onNavigateToVaultEditItemScreen,
|
||||||
|
onNavigateToVaultAddItemScreen = onNavigateToVaultAddItemScreen,
|
||||||
|
onNavigateToSearch = { onNavigateToSearchVault(it as SearchType.Vault) },
|
||||||
|
onNavigateToAddSendItem = {},
|
||||||
|
onNavigateToEditSendItem = {},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the [VaultItemListingScreen] to the nav graph.
|
* Add the [VaultItemListingScreen] to the nav graph.
|
||||||
*/
|
*/
|
||||||
|
@ -110,7 +148,9 @@ private fun NavGraphBuilder.internalVaultItemListingDestination(
|
||||||
arguments = listOf(
|
arguments = listOf(
|
||||||
navArgument(
|
navArgument(
|
||||||
name = VAULT_ITEM_LISTING_TYPE,
|
name = VAULT_ITEM_LISTING_TYPE,
|
||||||
builder = { type = NavType.StringType },
|
builder = {
|
||||||
|
type = NavType.StringType
|
||||||
|
},
|
||||||
),
|
),
|
||||||
navArgument(
|
navArgument(
|
||||||
name = ID,
|
name = ID,
|
||||||
|
@ -147,6 +187,20 @@ fun NavController.navigateToVaultItemListing(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to the [VaultItemListingScreen] for vault.
|
||||||
|
*/
|
||||||
|
fun NavController.navigateToVaultItemListingAsRoot(
|
||||||
|
vaultItemListingType: VaultItemListingType,
|
||||||
|
navOptions: NavOptions? = null,
|
||||||
|
) {
|
||||||
|
navigate(
|
||||||
|
route = "$VAULT_ITEM_LISTING_AS_ROOT_PREFIX/${vaultItemListingType.toTypeString()}" +
|
||||||
|
"?$ID=${vaultItemListingType.toIdOrNull()}",
|
||||||
|
navOptions = navOptions,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Navigate to the [VaultItemListingScreen] for sends.
|
* Navigate to the [VaultItemListingScreen] for sends.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -4,7 +4,10 @@ import android.os.Parcelable
|
||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import androidx.lifecycle.viewModelScope
|
import androidx.lifecycle.viewModelScope
|
||||||
import com.x8bit.bitwarden.R
|
import com.x8bit.bitwarden.R
|
||||||
|
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
||||||
|
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
||||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||||
|
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
||||||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
||||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||||
import com.x8bit.bitwarden.data.platform.repository.model.DataState
|
import com.x8bit.bitwarden.data.platform.repository.model.DataState
|
||||||
|
@ -44,7 +47,7 @@ import javax.inject.Inject
|
||||||
* and launches [VaultItemListingEvent] for the [VaultItemListingScreen].
|
* and launches [VaultItemListingEvent] for the [VaultItemListingScreen].
|
||||||
*/
|
*/
|
||||||
@HiltViewModel
|
@HiltViewModel
|
||||||
@Suppress("MagicNumber", "TooManyFunctions")
|
@Suppress("MagicNumber", "TooManyFunctions", "LongParameterList")
|
||||||
class VaultItemListingViewModel @Inject constructor(
|
class VaultItemListingViewModel @Inject constructor(
|
||||||
savedStateHandle: SavedStateHandle,
|
savedStateHandle: SavedStateHandle,
|
||||||
private val clock: Clock,
|
private val clock: Clock,
|
||||||
|
@ -52,8 +55,12 @@ class VaultItemListingViewModel @Inject constructor(
|
||||||
private val vaultRepository: VaultRepository,
|
private val vaultRepository: VaultRepository,
|
||||||
private val environmentRepository: EnvironmentRepository,
|
private val environmentRepository: EnvironmentRepository,
|
||||||
private val settingsRepository: SettingsRepository,
|
private val settingsRepository: SettingsRepository,
|
||||||
|
private val specialCircumstanceManager: SpecialCircumstanceManager,
|
||||||
) : BaseViewModel<VaultItemListingState, VaultItemListingEvent, VaultItemListingsAction>(
|
) : BaseViewModel<VaultItemListingState, VaultItemListingEvent, VaultItemListingsAction>(
|
||||||
initialState = VaultItemListingState(
|
initialState = run {
|
||||||
|
val specialCircumstance =
|
||||||
|
specialCircumstanceManager.specialCircumstance as? SpecialCircumstance.AutofillSelection
|
||||||
|
VaultItemListingState(
|
||||||
itemListingType = VaultItemListingArgs(savedStateHandle = savedStateHandle)
|
itemListingType = VaultItemListingArgs(savedStateHandle = savedStateHandle)
|
||||||
.vaultItemListingType
|
.vaultItemListingType
|
||||||
.toItemListingType(),
|
.toItemListingType(),
|
||||||
|
@ -64,7 +71,10 @@ class VaultItemListingViewModel @Inject constructor(
|
||||||
isIconLoadingDisabled = settingsRepository.isIconLoadingDisabled,
|
isIconLoadingDisabled = settingsRepository.isIconLoadingDisabled,
|
||||||
isPullToRefreshSettingEnabled = settingsRepository.getPullToRefreshEnabledFlow().value,
|
isPullToRefreshSettingEnabled = settingsRepository.getPullToRefreshEnabledFlow().value,
|
||||||
dialogState = null,
|
dialogState = null,
|
||||||
),
|
autofillSelectionData = specialCircumstance?.autofillSelectionData,
|
||||||
|
shouldFinishOnComplete = specialCircumstance?.shouldFinishWhenComplete ?: false,
|
||||||
|
)
|
||||||
|
},
|
||||||
) {
|
) {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -521,7 +531,10 @@ data class VaultItemListingState(
|
||||||
val baseIconUrl: String,
|
val baseIconUrl: String,
|
||||||
val isIconLoadingDisabled: Boolean,
|
val isIconLoadingDisabled: Boolean,
|
||||||
val dialogState: DialogState?,
|
val dialogState: DialogState?,
|
||||||
|
// Internal
|
||||||
private val isPullToRefreshSettingEnabled: Boolean,
|
private val isPullToRefreshSettingEnabled: Boolean,
|
||||||
|
private val autofillSelectionData: AutofillSelectionData? = null,
|
||||||
|
private val shouldFinishOnComplete: Boolean = false,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -530,6 +543,12 @@ data class VaultItemListingState(
|
||||||
val isPullToRefreshEnabled: Boolean
|
val isPullToRefreshEnabled: Boolean
|
||||||
get() = isPullToRefreshSettingEnabled && viewState.isPullToRefreshEnabled
|
get() = isPullToRefreshSettingEnabled && viewState.isPullToRefreshEnabled
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether or not this represents a listing screen for autofill.
|
||||||
|
*/
|
||||||
|
val isAutofill: Boolean
|
||||||
|
get() = autofillSelectionData != null
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the current state of any dialogs on the screen.
|
* Represents the current state of any dialogs on the screen.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -5,7 +5,8 @@ import androidx.lifecycle.SavedStateHandle
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||||
import com.x8bit.bitwarden.data.auth.repository.util.getCaptchaCallbackTokenResult
|
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
||||||
|
import com.x8bit.bitwarden.data.autofill.util.getAutofillSelectionDataOrNull
|
||||||
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManagerImpl
|
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManagerImpl
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
||||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||||
|
@ -107,7 +108,7 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
val mockIntent = mockk<Intent>()
|
val mockIntent = mockk<Intent>()
|
||||||
val shareData = mockk<IntentManager.ShareData>()
|
val shareData = mockk<IntentManager.ShareData>()
|
||||||
every { mockIntent.getCaptchaCallbackTokenResult() } returns null
|
every { mockIntent.getAutofillSelectionDataOrNull() } returns null
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns shareData
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns shareData
|
||||||
|
|
||||||
viewModel.trySendAction(
|
viewModel.trySendAction(
|
||||||
|
@ -124,13 +125,36 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("MaxLineLength")
|
||||||
|
@Test
|
||||||
|
fun `on ReceiveFirstIntent with autofill data should set the special circumstance to AutofillSelection`() {
|
||||||
|
val viewModel = createViewModel()
|
||||||
|
val mockIntent = mockk<Intent>()
|
||||||
|
val autofillSelectionData = mockk<AutofillSelectionData>()
|
||||||
|
every { mockIntent.getAutofillSelectionDataOrNull() } returns autofillSelectionData
|
||||||
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
|
|
||||||
|
viewModel.trySendAction(
|
||||||
|
MainAction.ReceiveFirstIntent(
|
||||||
|
intent = mockIntent,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
SpecialCircumstance.AutofillSelection(
|
||||||
|
autofillSelectionData = autofillSelectionData,
|
||||||
|
shouldFinishWhenComplete = true,
|
||||||
|
),
|
||||||
|
specialCircumstanceManager.specialCircumstance,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("MaxLineLength")
|
@Suppress("MaxLineLength")
|
||||||
@Test
|
@Test
|
||||||
fun `on ReceiveNewIntent with share data should set the special circumstance to ShareNewSend`() {
|
fun `on ReceiveNewIntent with share data should set the special circumstance to ShareNewSend`() {
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
val mockIntent = mockk<Intent>()
|
val mockIntent = mockk<Intent>()
|
||||||
val shareData = mockk<IntentManager.ShareData>()
|
val shareData = mockk<IntentManager.ShareData>()
|
||||||
every { mockIntent.getCaptchaCallbackTokenResult() } returns null
|
every { mockIntent.getAutofillSelectionDataOrNull() } returns null
|
||||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns shareData
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns shareData
|
||||||
|
|
||||||
viewModel.trySendAction(
|
viewModel.trySendAction(
|
||||||
|
@ -147,6 +171,29 @@ class MainViewModelTest : BaseViewModelTest() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("MaxLineLength")
|
||||||
|
@Test
|
||||||
|
fun `on ReceiveNewIntent with autofill data should set the special circumstance to AutofillSelection`() {
|
||||||
|
val viewModel = createViewModel()
|
||||||
|
val mockIntent = mockk<Intent>()
|
||||||
|
val autofillSelectionData = mockk<AutofillSelectionData>()
|
||||||
|
every { mockIntent.getAutofillSelectionDataOrNull() } returns autofillSelectionData
|
||||||
|
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||||
|
|
||||||
|
viewModel.trySendAction(
|
||||||
|
MainAction.ReceiveNewIntent(
|
||||||
|
intent = mockIntent,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
assertEquals(
|
||||||
|
SpecialCircumstance.AutofillSelection(
|
||||||
|
autofillSelectionData = autofillSelectionData,
|
||||||
|
shouldFinishWhenComplete = false,
|
||||||
|
),
|
||||||
|
specialCircumstanceManager.specialCircumstance,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Suppress("MaxLineLength")
|
@Suppress("MaxLineLength")
|
||||||
@Test
|
@Test
|
||||||
fun `changes in the allowed screen capture value should result in emissions of ScreenCaptureSettingChange `() =
|
fun `changes in the allowed screen capture value should result in emissions of ScreenCaptureSettingChange `() =
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package com.x8bit.bitwarden.ui.platform.feature.rootnav
|
package com.x8bit.bitwarden.ui.platform.feature.rootnav
|
||||||
|
|
||||||
import androidx.navigation.navOptions
|
import androidx.navigation.navOptions
|
||||||
|
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
||||||
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||||
import com.x8bit.bitwarden.ui.platform.base.FakeNavHostController
|
import com.x8bit.bitwarden.ui.platform.base.FakeNavHostController
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
|
@ -98,5 +99,17 @@ class RootNavScreenTest : BaseComposeTest() {
|
||||||
navOptions = expectedNavOptions,
|
navOptions = expectedNavOptions,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Make sure navigating to vault unlocked for autofill works as expected:
|
||||||
|
rootNavStateFlow.value =
|
||||||
|
RootNavState.VaultUnlockedForAutofillSelection(
|
||||||
|
type = AutofillSelectionData.Type.LOGIN,
|
||||||
|
)
|
||||||
|
composeTestRule.runOnIdle {
|
||||||
|
fakeNavHostController.assertLastNavigation(
|
||||||
|
route = "vault_item_listing_as_root/login",
|
||||||
|
navOptions = expectedNavOptions,
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,7 @@ package com.x8bit.bitwarden.ui.platform.feature.rootnav
|
||||||
|
|
||||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||||
|
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
||||||
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManagerImpl
|
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManagerImpl
|
||||||
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
||||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||||
|
@ -145,6 +146,46 @@ class RootNavViewModelTest : BaseViewModelTest() {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("MaxLineLength")
|
||||||
|
@Test
|
||||||
|
fun `when the active user has an unlocked vault but there is an AutofillSelection special circumstance the nav state should be VaultUnlockedForAutofillSelection`() {
|
||||||
|
val autofillSelectionData = AutofillSelectionData(
|
||||||
|
type = AutofillSelectionData.Type.LOGIN,
|
||||||
|
uri = "uri",
|
||||||
|
)
|
||||||
|
specialCircumstanceManager.specialCircumstance =
|
||||||
|
SpecialCircumstance.AutofillSelection(
|
||||||
|
autofillSelectionData = autofillSelectionData,
|
||||||
|
shouldFinishWhenComplete = true,
|
||||||
|
)
|
||||||
|
mutableUserStateFlow.tryEmit(
|
||||||
|
UserState(
|
||||||
|
activeUserId = "activeUserId",
|
||||||
|
accounts = listOf(
|
||||||
|
UserState.Account(
|
||||||
|
userId = "activeUserId",
|
||||||
|
name = "name",
|
||||||
|
email = "email",
|
||||||
|
avatarColorHex = "avatarColorHex",
|
||||||
|
environment = Environment.Us,
|
||||||
|
isPremium = true,
|
||||||
|
isLoggedIn = true,
|
||||||
|
isVaultUnlocked = true,
|
||||||
|
isBiometricsEnabled = false,
|
||||||
|
organizations = emptyList(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
val viewModel = createViewModel()
|
||||||
|
assertEquals(
|
||||||
|
RootNavState.VaultUnlockedForAutofillSelection(
|
||||||
|
type = AutofillSelectionData.Type.LOGIN,
|
||||||
|
),
|
||||||
|
viewModel.stateFlow.value,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `when the active user has a locked vault the nav state should be VaultLocked`() {
|
fun `when the active user has a locked vault the nav state should be VaultLocked`() {
|
||||||
mutableUserStateFlow.tryEmit(
|
mutableUserStateFlow.tryEmit(
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package com.x8bit.bitwarden.ui.platform.feature.rootnav.util
|
||||||
|
|
||||||
|
import com.x8bit.bitwarden.data.autofill.model.AutofillSelectionData
|
||||||
|
import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType
|
||||||
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
class AutofillSelectionDataExtensionsTest {
|
||||||
|
@Test
|
||||||
|
fun `toVaultItemListingType should return the correct result for each type`() {
|
||||||
|
mapOf(
|
||||||
|
AutofillSelectionData.Type.CARD to VaultItemListingType.Card,
|
||||||
|
AutofillSelectionData.Type.LOGIN to VaultItemListingType.Login,
|
||||||
|
)
|
||||||
|
.forEach { (type, expected) ->
|
||||||
|
assertEquals(
|
||||||
|
expected,
|
||||||
|
type.toVaultItemListingType(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import android.net.Uri
|
||||||
import androidx.lifecycle.SavedStateHandle
|
import androidx.lifecycle.SavedStateHandle
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.x8bit.bitwarden.R
|
import com.x8bit.bitwarden.R
|
||||||
|
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManagerImpl
|
||||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
||||||
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
||||||
|
@ -76,6 +77,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||||
every { isIconLoadingDisabledFlow } returns mutableIsIconLoadingDisabledFlow
|
every { isIconLoadingDisabledFlow } returns mutableIsIconLoadingDisabledFlow
|
||||||
every { getPullToRefreshEnabledFlow() } returns mutablePullToRefreshEnabledFlow
|
every { getPullToRefreshEnabledFlow() } returns mutablePullToRefreshEnabledFlow
|
||||||
}
|
}
|
||||||
|
private val specialCircumstanceManager = SpecialCircumstanceManagerImpl()
|
||||||
private val initialState = createVaultItemListingState()
|
private val initialState = createVaultItemListingState()
|
||||||
private val initialSavedStateHandle = createSavedStateHandleWithVaultItemListingType(
|
private val initialSavedStateHandle = createSavedStateHandleWithVaultItemListingType(
|
||||||
vaultItemListingType = VaultItemListingType.Login,
|
vaultItemListingType = VaultItemListingType.Login,
|
||||||
|
@ -941,6 +943,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||||
vaultRepository = vaultRepository,
|
vaultRepository = vaultRepository,
|
||||||
environmentRepository = environmentRepository,
|
environmentRepository = environmentRepository,
|
||||||
settingsRepository = settingsRepository,
|
settingsRepository = settingsRepository,
|
||||||
|
specialCircumstanceManager = specialCircumstanceManager,
|
||||||
)
|
)
|
||||||
|
|
||||||
@Suppress("MaxLineLength")
|
@Suppress("MaxLineLength")
|
||||||
|
@ -957,5 +960,7 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||||
isIconLoadingDisabled = settingsRepository.isIconLoadingDisabled,
|
isIconLoadingDisabled = settingsRepository.isIconLoadingDisabled,
|
||||||
isPullToRefreshSettingEnabled = false,
|
isPullToRefreshSettingEnabled = false,
|
||||||
dialogState = null,
|
dialogState = null,
|
||||||
|
autofillSelectionData = null,
|
||||||
|
shouldFinishOnComplete = false,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue