mirror of
https://github.com/bitwarden/android.git
synced 2025-03-15 18:58:59 +03:00
Replace usages of compose ClipboardManager in UI with BitwardenClipboardManager in ViewModels (#502)
This commit is contained in:
parent
8d5de22c72
commit
889855d261
25 changed files with 316 additions and 392 deletions
|
@ -0,0 +1,42 @@
|
|||
package com.x8bit.bitwarden.data.platform.manager.clipboard
|
||||
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||
|
||||
/**
|
||||
* Wrapper class for using the clipboard.
|
||||
*/
|
||||
interface BitwardenClipboardManager {
|
||||
|
||||
/**
|
||||
* Places the given [text] into the device's clipboard. Setting the data to [isSensitive] will
|
||||
* obfuscate the displayed data on the default popup (true by default). A toast will be
|
||||
* displayed on devices that do not have a default popup (pre-API 32) and will not be displayed
|
||||
* on newer APIs. If a toast is displayed, it will be formatted as "[text] copied" or if a
|
||||
* [toastDescriptorOverride] is provided, it will be formatted as
|
||||
* "[toastDescriptorOverride] copied".
|
||||
*/
|
||||
fun setText(
|
||||
text: AnnotatedString,
|
||||
isSensitive: Boolean = true,
|
||||
toastDescriptorOverride: String? = null,
|
||||
)
|
||||
|
||||
/**
|
||||
* See [setText] for more details.
|
||||
*/
|
||||
fun setText(
|
||||
text: String,
|
||||
isSensitive: Boolean = true,
|
||||
toastDescriptorOverride: String? = null,
|
||||
)
|
||||
|
||||
/**
|
||||
* See [setText] for more details.
|
||||
*/
|
||||
fun setText(
|
||||
text: Text,
|
||||
isSensitive: Boolean = true,
|
||||
toastDescriptorOverride: String? = null,
|
||||
)
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package com.x8bit.bitwarden.data.platform.manager.clipboard
|
||||
|
||||
import android.content.ClipData
|
||||
import android.content.ClipboardManager
|
||||
import android.content.Context
|
||||
import android.os.Build
|
||||
import android.widget.Toast
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.core.content.getSystemService
|
||||
import androidx.core.os.persistableBundleOf
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.toAnnotatedString
|
||||
|
||||
/**
|
||||
* Default implementation of the [BitwardenClipboardManager] interface.
|
||||
*/
|
||||
@OmitFromCoverage
|
||||
class BitwardenClipboardManagerImpl(
|
||||
private val context: Context,
|
||||
) : BitwardenClipboardManager {
|
||||
private val clipboardManager: ClipboardManager = requireNotNull(context.getSystemService())
|
||||
|
||||
override fun setText(
|
||||
text: AnnotatedString,
|
||||
isSensitive: Boolean,
|
||||
toastDescriptorOverride: String?,
|
||||
) {
|
||||
clipboardManager.setPrimaryClip(
|
||||
ClipData
|
||||
.newPlainText("", text)
|
||||
.apply {
|
||||
description.extras = persistableBundleOf(
|
||||
"android.content.extra.IS_SENSITIVE" to isSensitive,
|
||||
)
|
||||
},
|
||||
)
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.S_V2) {
|
||||
val descriptor = toastDescriptorOverride ?: text
|
||||
Toast
|
||||
.makeText(
|
||||
context,
|
||||
context.resources.getString(R.string.value_has_been_copied, descriptor),
|
||||
Toast.LENGTH_SHORT,
|
||||
)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
||||
override fun setText(text: String, isSensitive: Boolean, toastDescriptorOverride: String?) {
|
||||
setText(text.toAnnotatedString(), isSensitive, toastDescriptorOverride)
|
||||
}
|
||||
|
||||
override fun setText(text: Text, isSensitive: Boolean, toastDescriptorOverride: String?) {
|
||||
setText(text.toString(context.resources), isSensitive, toastDescriptorOverride)
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package com.x8bit.bitwarden.data.platform.manager.di
|
||||
|
||||
import android.content.Context
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.platform.datasource.network.authenticator.RefreshAuthenticator
|
||||
import com.x8bit.bitwarden.data.platform.datasource.network.interceptor.AuthTokenInterceptor
|
||||
|
@ -8,12 +9,15 @@ import com.x8bit.bitwarden.data.platform.manager.NetworkConfigManager
|
|||
import com.x8bit.bitwarden.data.platform.manager.NetworkConfigManagerImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.SdkClientManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.SdkClientManagerImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManagerImpl
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManagerImpl
|
||||
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import dagger.hilt.components.SingletonComponent
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
@ -24,6 +28,12 @@ import javax.inject.Singleton
|
|||
@InstallIn(SingletonComponent::class)
|
||||
object PlatformManagerModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideBitwardenClipboardManager(
|
||||
@ApplicationContext context: Context,
|
||||
): BitwardenClipboardManager = BitwardenClipboardManagerImpl(context)
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun provideBitwardenDispatchers(): DispatcherManager = DispatcherManagerImpl()
|
||||
|
|
|
@ -29,8 +29,6 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.ClipboardManager
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
@ -46,7 +44,6 @@ import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
|||
import com.x8bit.bitwarden.ui.platform.base.util.IntentHandler
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.toAnnotatedString
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenExternalLinkRow
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenScaffold
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenTopAppBar
|
||||
|
@ -62,7 +59,6 @@ import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
|||
fun AboutScreen(
|
||||
onNavigateBack: () -> Unit,
|
||||
viewModel: AboutViewModel = hiltViewModel(),
|
||||
clipboardManager: ClipboardManager = LocalClipboardManager.current,
|
||||
intentHandler: IntentHandler = IntentHandler(context = LocalContext.current),
|
||||
) {
|
||||
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||
|
@ -70,10 +66,6 @@ fun AboutScreen(
|
|||
val resources = context.resources
|
||||
EventsEffect(viewModel = viewModel) { event ->
|
||||
when (event) {
|
||||
is AboutEvent.CopyToClipboard -> {
|
||||
clipboardManager.setText(event.text.toString(resources).toAnnotatedString())
|
||||
}
|
||||
|
||||
AboutEvent.NavigateBack -> onNavigateBack.invoke()
|
||||
|
||||
AboutEvent.NavigateToHelpCenter -> {
|
||||
|
|
|
@ -5,6 +5,7 @@ import androidx.lifecycle.SavedStateHandle
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import com.x8bit.bitwarden.BuildConfig
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.Text
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
|
@ -24,6 +25,7 @@ private const val KEY_STATE = "state"
|
|||
@HiltViewModel
|
||||
class AboutViewModel @Inject constructor(
|
||||
private val savedStateHandle: SavedStateHandle,
|
||||
private val clipboardManager: BitwardenClipboardManager,
|
||||
) : BaseViewModel<AboutState, AboutEvent, AboutAction>(
|
||||
initialState = savedStateHandle[KEY_STATE] ?: INITIAL_STATE,
|
||||
) {
|
||||
|
@ -67,7 +69,7 @@ class AboutViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun handleVersionClick() {
|
||||
sendEvent(AboutEvent.CopyToClipboard(text = stateFlow.value.version))
|
||||
clipboardManager.setText(text = state.version)
|
||||
}
|
||||
|
||||
private fun handleWebVaultClick() {
|
||||
|
@ -97,13 +99,6 @@ data class AboutState(
|
|||
* Models events for the about screen.
|
||||
*/
|
||||
sealed class AboutEvent {
|
||||
/**
|
||||
* Copy the given [text] to the clipboard.
|
||||
*/
|
||||
data class CopyToClipboard(
|
||||
val text: Text,
|
||||
) : AboutEvent()
|
||||
|
||||
/**
|
||||
* Navigate back.
|
||||
*/
|
||||
|
|
|
@ -33,14 +33,11 @@ import androidx.compose.ui.Alignment
|
|||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.layout.onGloballyPositioned
|
||||
import androidx.compose.ui.platform.ClipboardManager
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalDensity
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.semantics.semantics
|
||||
import androidx.compose.ui.text.AnnotatedString
|
||||
import androidx.compose.ui.text.input.KeyboardType
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.Dp
|
||||
|
@ -87,7 +84,6 @@ import kotlinx.collections.immutable.toImmutableList
|
|||
fun GeneratorScreen(
|
||||
viewModel: GeneratorViewModel = hiltViewModel(),
|
||||
onNavigateToPasswordHistory: () -> Unit,
|
||||
clipboardManager: ClipboardManager = LocalClipboardManager.current,
|
||||
) {
|
||||
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
|
@ -98,10 +94,6 @@ fun GeneratorScreen(
|
|||
when (event) {
|
||||
GeneratorEvent.NavigateToPasswordHistory -> onNavigateToPasswordHistory()
|
||||
|
||||
GeneratorEvent.CopyTextToClipboard -> {
|
||||
clipboardManager.setText(AnnotatedString(state.generatedText))
|
||||
}
|
||||
|
||||
is GeneratorEvent.ShowSnackbar -> {
|
||||
snackbarHostState.showSnackbar(
|
||||
message = event.message(resources).toString(),
|
||||
|
|
|
@ -11,6 +11,7 @@ import com.bitwarden.core.PasswordGeneratorRequest
|
|||
import com.bitwarden.core.UsernameGeneratorRequest
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||
import com.x8bit.bitwarden.data.tools.generator.repository.GeneratorRepository
|
||||
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedForwardedServiceUsernameResult
|
||||
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPassphraseResult
|
||||
|
@ -59,6 +60,7 @@ private const val KEY_STATE = "state"
|
|||
@HiltViewModel
|
||||
class GeneratorViewModel @Inject constructor(
|
||||
private val savedStateHandle: SavedStateHandle,
|
||||
private val clipboardManager: BitwardenClipboardManager,
|
||||
private val generatorRepository: GeneratorRepository,
|
||||
private val authRepository: AuthRepository,
|
||||
) : BaseViewModel<GeneratorState, GeneratorEvent, GeneratorAction>(
|
||||
|
@ -328,7 +330,7 @@ class GeneratorViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun handleCopyClick() {
|
||||
sendEvent(GeneratorEvent.CopyTextToClipboard)
|
||||
clipboardManager.setText(text = state.generatedText)
|
||||
}
|
||||
|
||||
private fun handleUpdateGeneratedPasswordResult(
|
||||
|
@ -1949,11 +1951,6 @@ sealed class GeneratorEvent {
|
|||
*/
|
||||
data object NavigateToPasswordHistory : GeneratorEvent()
|
||||
|
||||
/**
|
||||
* Copies text to the clipboard.
|
||||
*/
|
||||
data object CopyTextToClipboard : GeneratorEvent()
|
||||
|
||||
/**
|
||||
* Displays the message in a snackbar.
|
||||
*/
|
||||
|
|
|
@ -25,8 +25,6 @@ import androidx.compose.runtime.remember
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.ClipboardManager
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
@ -35,7 +33,6 @@ import androidx.hilt.navigation.compose.hiltViewModel
|
|||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.toAnnotatedString
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenOverflowActionItem
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenScaffold
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenTopAppBar
|
||||
|
@ -51,7 +48,6 @@ import kotlinx.collections.immutable.persistentListOf
|
|||
fun PasswordHistoryScreen(
|
||||
onNavigateBack: () -> Unit,
|
||||
viewModel: PasswordHistoryViewModel = hiltViewModel(),
|
||||
clipboardManager: ClipboardManager = LocalClipboardManager.current,
|
||||
) {
|
||||
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
|
@ -61,10 +57,6 @@ fun PasswordHistoryScreen(
|
|||
when (event) {
|
||||
PasswordHistoryEvent.NavigateBack -> onNavigateBack.invoke()
|
||||
|
||||
is PasswordHistoryEvent.CopyTextToClipboard -> {
|
||||
clipboardManager.setText(event.text.toAnnotatedString())
|
||||
}
|
||||
|
||||
is PasswordHistoryEvent.ShowToast -> {
|
||||
Toast.makeText(context, event.message, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.os.Parcelable
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import com.bitwarden.core.PasswordHistoryView
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.LocalDataState
|
||||
import com.x8bit.bitwarden.data.tools.generator.repository.GeneratorRepository
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||
|
@ -26,6 +27,7 @@ import javax.inject.Inject
|
|||
@HiltViewModel
|
||||
@Suppress("TooManyFunctions")
|
||||
class PasswordHistoryViewModel @Inject constructor(
|
||||
private val clipboardManager: BitwardenClipboardManager,
|
||||
private val generatorRepository: GeneratorRepository,
|
||||
) : BaseViewModel<PasswordHistoryState, PasswordHistoryEvent, PasswordHistoryAction>(
|
||||
initialState = PasswordHistoryState(PasswordHistoryState.ViewState.Loading),
|
||||
|
@ -96,7 +98,7 @@ class PasswordHistoryViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
private fun handleCopyClick(password: GeneratedPassword) {
|
||||
sendEvent(PasswordHistoryEvent.CopyTextToClipboard(password.password))
|
||||
clipboardManager.setText(text = password.password)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -174,11 +176,6 @@ sealed class PasswordHistoryEvent {
|
|||
* Event to navigate back to the previous screen.
|
||||
*/
|
||||
data object NavigateBack : PasswordHistoryEvent()
|
||||
|
||||
/**
|
||||
* Copies text to the clipboard.
|
||||
*/
|
||||
data class CopyTextToClipboard(val text: String) : PasswordHistoryEvent()
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,8 +18,6 @@ import androidx.compose.runtime.getValue
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.ClipboardManager
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
@ -29,7 +27,6 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
|||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.IntentHandler
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.toAnnotatedString
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenErrorContent
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenLoadingContent
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenMediumTopAppBar
|
||||
|
@ -49,19 +46,12 @@ import kotlinx.collections.immutable.persistentListOf
|
|||
fun SendScreen(
|
||||
onNavigateToAddSend: () -> Unit,
|
||||
viewModel: SendViewModel = hiltViewModel(),
|
||||
clipboardManager: ClipboardManager = LocalClipboardManager.current,
|
||||
intentHandler: IntentHandler = IntentHandler(context = LocalContext.current),
|
||||
) {
|
||||
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
EventsEffect(viewModel = viewModel) { event ->
|
||||
when (event) {
|
||||
is SendEvent.CopyToClipboard -> {
|
||||
clipboardManager.setText(
|
||||
event.message(context.resources).toString().toAnnotatedString(),
|
||||
)
|
||||
}
|
||||
|
||||
is SendEvent.NavigateNewSend -> onNavigateToAddSend()
|
||||
|
||||
is SendEvent.NavigateToAboutSend -> {
|
||||
|
|
|
@ -5,6 +5,7 @@ import androidx.annotation.DrawableRes
|
|||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.DataState
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.SendData
|
||||
|
@ -32,6 +33,7 @@ private const val KEY_STATE = "state"
|
|||
@HiltViewModel
|
||||
class SendViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val clipboardManager: BitwardenClipboardManager,
|
||||
private val vaultRepo: VaultRepository,
|
||||
) : BaseViewModel<SendState, SendEvent, SendAction>(
|
||||
// We load the state from the savedStateHandle for testing purposes.
|
||||
|
@ -324,11 +326,6 @@ sealed class SendAction {
|
|||
* Models events for the send screen.
|
||||
*/
|
||||
sealed class SendEvent {
|
||||
/**
|
||||
* Copies the given [message] to the clipboard.
|
||||
*/
|
||||
data class CopyToClipboard(val message: Text) : SendEvent()
|
||||
|
||||
/**
|
||||
* Navigate to the new send screen.
|
||||
*/
|
||||
|
|
|
@ -13,8 +13,6 @@ import androidx.compose.runtime.getValue
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.ClipboardManager
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
@ -25,7 +23,6 @@ import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
|||
import com.x8bit.bitwarden.ui.platform.base.util.PermissionsManager
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.PermissionsManagerImpl
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.toAnnotatedString
|
||||
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenBasicDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenErrorContent
|
||||
|
@ -50,7 +47,6 @@ fun VaultAddEditScreen(
|
|||
onNavigateBack: () -> Unit,
|
||||
onNavigateToQrCodeScanScreen: () -> Unit,
|
||||
viewModel: VaultAddEditViewModel = hiltViewModel(),
|
||||
clipboardManager: ClipboardManager = LocalClipboardManager.current,
|
||||
permissionsManager: PermissionsManager =
|
||||
PermissionsManagerImpl(LocalContext.current as Activity),
|
||||
) {
|
||||
|
@ -68,10 +64,6 @@ fun VaultAddEditScreen(
|
|||
Toast.makeText(context, event.message(resources), Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
is VaultAddEditEvent.CopyToClipboard -> {
|
||||
clipboardManager.setText(event.text.toAnnotatedString())
|
||||
}
|
||||
|
||||
VaultAddEditEvent.NavigateBack -> onNavigateBack.invoke()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import androidx.lifecycle.SavedStateHandle
|
|||
import androidx.lifecycle.viewModelScope
|
||||
import com.bitwarden.core.CipherView
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.DataState
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.takeUntilLoaded
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
|
@ -48,6 +49,7 @@ private const val KEY_STATE = "state"
|
|||
@Suppress("TooManyFunctions", "LargeClass")
|
||||
class VaultAddEditViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val clipboardManager: BitwardenClipboardManager,
|
||||
private val vaultRepository: VaultRepository,
|
||||
) : BaseViewModel<VaultAddEditState, VaultAddEditEvent, VaultAddEditAction>(
|
||||
// We load the state from the savedStateHandle for testing purposes.
|
||||
|
@ -435,11 +437,7 @@ class VaultAddEditViewModel @Inject constructor(
|
|||
private fun handleLoginCopyTotpKeyText(
|
||||
action: VaultAddEditAction.ItemType.LoginType.CopyTotpKeyClick,
|
||||
) {
|
||||
sendEvent(
|
||||
event = VaultAddEditEvent.CopyToClipboard(
|
||||
text = action.totpKey,
|
||||
),
|
||||
)
|
||||
clipboardManager.setText(text = action.totpKey)
|
||||
}
|
||||
|
||||
private fun handleLoginUriSettingsClick() {
|
||||
|
@ -1226,11 +1224,6 @@ sealed class VaultAddEditEvent {
|
|||
*/
|
||||
data class ShowToast(val message: Text) : VaultAddEditEvent()
|
||||
|
||||
/**
|
||||
* Copy the given [text] to the clipboard.
|
||||
*/
|
||||
data class CopyToClipboard(val text: String) : VaultAddEditEvent()
|
||||
|
||||
/**
|
||||
* Navigate back to previous screen.
|
||||
*/
|
||||
|
|
|
@ -18,8 +18,6 @@ import androidx.compose.runtime.getValue
|
|||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.ClipboardManager
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
|
@ -31,7 +29,6 @@ import com.x8bit.bitwarden.R
|
|||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.IntentHandler
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.toAnnotatedString
|
||||
import com.x8bit.bitwarden.ui.platform.components.BasicDialogState
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenBasicDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenErrorContent
|
||||
|
@ -53,7 +50,6 @@ import com.x8bit.bitwarden.ui.vault.feature.item.handlers.VaultLoginItemTypeHand
|
|||
@Composable
|
||||
fun VaultItemScreen(
|
||||
viewModel: VaultItemViewModel = hiltViewModel(),
|
||||
clipboardManager: ClipboardManager = LocalClipboardManager.current,
|
||||
intentHandler: IntentHandler = IntentHandler(context = LocalContext.current),
|
||||
onNavigateBack: () -> Unit,
|
||||
onNavigateToVaultEditItem: (vaultItemId: String) -> Unit,
|
||||
|
@ -63,10 +59,6 @@ fun VaultItemScreen(
|
|||
val resources = context.resources
|
||||
EventsEffect(viewModel = viewModel) { event ->
|
||||
when (event) {
|
||||
is VaultItemEvent.CopyToClipboard -> {
|
||||
clipboardManager.setText(event.message.toString(resources).toAnnotatedString())
|
||||
}
|
||||
|
||||
VaultItemEvent.NavigateBack -> onNavigateBack()
|
||||
|
||||
is VaultItemEvent.NavigateToEdit -> onNavigateToVaultEditItem(event.itemId)
|
||||
|
|
|
@ -8,6 +8,7 @@ import com.x8bit.bitwarden.R
|
|||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.BreachCountResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.DataState
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.VerifyPasswordResult
|
||||
|
@ -36,6 +37,7 @@ private const val KEY_STATE = "state"
|
|||
@HiltViewModel
|
||||
class VaultItemViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
private val clipboardManager: BitwardenClipboardManager,
|
||||
private val authRepository: AuthRepository,
|
||||
private val vaultRepository: VaultRepository,
|
||||
) : BaseViewModel<VaultItemState, VaultItemEvent, VaultItemAction>(
|
||||
|
@ -148,14 +150,14 @@ class VaultItemViewModel @Inject constructor(
|
|||
}
|
||||
return@onContent
|
||||
}
|
||||
sendEvent(VaultItemEvent.CopyToClipboard(action.field.asText()))
|
||||
clipboardManager.setText(text = action.field)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleCopyCustomTextFieldClick(
|
||||
action: VaultItemAction.Common.CopyCustomTextFieldClick,
|
||||
) {
|
||||
sendEvent(VaultItemEvent.CopyToClipboard(action.field.asText()))
|
||||
clipboardManager.setText(text = action.field)
|
||||
}
|
||||
|
||||
private fun handleHiddenFieldVisibilityClicked(
|
||||
|
@ -244,12 +246,12 @@ class VaultItemViewModel @Inject constructor(
|
|||
return@onLoginContent
|
||||
}
|
||||
val password = requireNotNull(login.passwordData?.password)
|
||||
sendEvent(VaultItemEvent.CopyToClipboard(password.asText()))
|
||||
clipboardManager.setText(text = password)
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleCopyUriClick(action: VaultItemAction.ItemType.Login.CopyUriClick) {
|
||||
sendEvent(VaultItemEvent.CopyToClipboard(action.uri.asText()))
|
||||
clipboardManager.setText(text = action.uri)
|
||||
}
|
||||
|
||||
private fun handleCopyUsernameClick() {
|
||||
|
@ -261,7 +263,7 @@ class VaultItemViewModel @Inject constructor(
|
|||
return@onLoginContent
|
||||
}
|
||||
val username = requireNotNull(login.username)
|
||||
sendEvent(VaultItemEvent.CopyToClipboard(username.asText()))
|
||||
clipboardManager.setText(text = username)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -681,13 +683,6 @@ data class VaultItemState(
|
|||
* Represents a set of events related view a vault item.
|
||||
*/
|
||||
sealed class VaultItemEvent {
|
||||
/**
|
||||
* Places the given [message] in your clipboard.
|
||||
*/
|
||||
data class CopyToClipboard(
|
||||
val message: Text,
|
||||
) : VaultItemEvent()
|
||||
|
||||
/**
|
||||
* Navigates back.
|
||||
*/
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.x8bit.bitwarden.ui.platform.feature.settings.about
|
||||
|
||||
import androidx.compose.ui.platform.ClipboardManager
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertIsOff
|
||||
import androidx.compose.ui.test.assertIsOn
|
||||
|
@ -15,7 +14,6 @@ import androidx.core.net.toUri
|
|||
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.IntentHandler
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.toAnnotatedString
|
||||
import io.mockk.Runs
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
|
@ -108,28 +106,6 @@ class AboutScreenTest : BaseComposeTest() {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on CopyToClipboard should call setText on ClipboardManager`() {
|
||||
val text = "copy text"
|
||||
val clipboardManager = mockk<ClipboardManager> {
|
||||
every { setText(any()) } just Runs
|
||||
}
|
||||
val viewModel = mockk<AboutViewModel> {
|
||||
every { stateFlow } returns mutableStateFlow
|
||||
every { eventFlow } returns flowOf(AboutEvent.CopyToClipboard(text.asText()))
|
||||
}
|
||||
composeTestRule.setContent {
|
||||
AboutScreen(
|
||||
viewModel = viewModel,
|
||||
onNavigateBack = { },
|
||||
clipboardManager = clipboardManager,
|
||||
)
|
||||
}
|
||||
verify {
|
||||
clipboardManager.setText(text.toAnnotatedString())
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `on learn about organizations click should display confirmation dialog and confirm click should emit LearnAboutOrganizationsClick`() {
|
||||
|
|
|
@ -2,8 +2,14 @@ package com.x8bit.bitwarden.ui.platform.feature.settings.about
|
|||
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.runs
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
|
@ -12,12 +18,11 @@ import org.junit.jupiter.api.Test
|
|||
|
||||
class AboutViewModelTest : BaseViewModelTest() {
|
||||
|
||||
private val initialState = createAboutState()
|
||||
private val initialSavedStateHandle = createSavedStateHandleWithState(initialState)
|
||||
private val clipboardManager: BitwardenClipboardManager = mockk()
|
||||
|
||||
@Test
|
||||
fun `on BackClick should emit NavigateBack`() = runTest {
|
||||
val viewModel = AboutViewModel(initialSavedStateHandle)
|
||||
val viewModel = createViewModel(DEFAULT_ABOUT_STATE)
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(AboutAction.BackClick)
|
||||
assertEquals(AboutEvent.NavigateBack, awaitItem())
|
||||
|
@ -26,7 +31,7 @@ class AboutViewModelTest : BaseViewModelTest() {
|
|||
|
||||
@Test
|
||||
fun `on HelpCenterClick should emit NavigateToHelpCenter`() = runTest {
|
||||
val viewModel = AboutViewModel(initialSavedStateHandle)
|
||||
val viewModel = createViewModel(DEFAULT_ABOUT_STATE)
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(AboutAction.HelpCenterClick)
|
||||
assertEquals(AboutEvent.NavigateToHelpCenter, awaitItem())
|
||||
|
@ -36,7 +41,7 @@ class AboutViewModelTest : BaseViewModelTest() {
|
|||
@Test
|
||||
fun `on LearnAboutOrganizationsClick should emit NavigateToLearnAboutOrganizations`() =
|
||||
runTest {
|
||||
val viewModel = AboutViewModel(initialSavedStateHandle)
|
||||
val viewModel = createViewModel(DEFAULT_ABOUT_STATE)
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(AboutAction.LearnAboutOrganizationsClick)
|
||||
assertEquals(AboutEvent.NavigateToLearnAboutOrganizations, awaitItem())
|
||||
|
@ -45,7 +50,7 @@ class AboutViewModelTest : BaseViewModelTest() {
|
|||
|
||||
@Test
|
||||
fun `on RateAppClick should emit ShowToast`() = runTest {
|
||||
val viewModel = AboutViewModel(initialSavedStateHandle)
|
||||
val viewModel = createViewModel(DEFAULT_ABOUT_STATE)
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(AboutAction.RateAppClick)
|
||||
assertEquals(AboutEvent.ShowToast("Navigate to rate the app.".asText()), awaitItem())
|
||||
|
@ -54,38 +59,42 @@ class AboutViewModelTest : BaseViewModelTest() {
|
|||
|
||||
@Test
|
||||
fun `on SubmitCrashLogsClick should update isSubmitCrashLogsEnabled to true`() = runTest {
|
||||
val viewModel = AboutViewModel(initialSavedStateHandle)
|
||||
val viewModel = createViewModel(DEFAULT_ABOUT_STATE)
|
||||
assertFalse(viewModel.stateFlow.value.isSubmitCrashLogsEnabled)
|
||||
viewModel.trySendAction(AboutAction.SubmitCrashLogsClick(true))
|
||||
assertTrue(viewModel.stateFlow.value.isSubmitCrashLogsEnabled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on VersionClick should emit CopyToClipboard`() = runTest {
|
||||
val viewModel = AboutViewModel(initialSavedStateHandle)
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(AboutAction.VersionClick)
|
||||
assertEquals(AboutEvent.CopyToClipboard("0".asText()), awaitItem())
|
||||
fun `on VersionClick should call setText on the ClipboardManager`() {
|
||||
val viewModel = createViewModel(DEFAULT_ABOUT_STATE)
|
||||
every { clipboardManager.setText(text = "0".asText()) } just runs
|
||||
|
||||
viewModel.trySendAction(AboutAction.VersionClick)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(text = "0".asText())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on WebVaultClick should emit NavigateToWebVault`() = runTest {
|
||||
val viewModel = AboutViewModel(initialSavedStateHandle)
|
||||
val viewModel = createViewModel(DEFAULT_ABOUT_STATE)
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(AboutAction.WebVaultClick)
|
||||
assertEquals(AboutEvent.NavigateToWebVault, awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
private fun createAboutState(): AboutState =
|
||||
AboutState(
|
||||
version = "0".asText(),
|
||||
isSubmitCrashLogsEnabled = false,
|
||||
)
|
||||
|
||||
private fun createSavedStateHandleWithState(state: AboutState) =
|
||||
SavedStateHandle().apply {
|
||||
set("state", state)
|
||||
}
|
||||
private fun createViewModel(
|
||||
state: AboutState? = null,
|
||||
): AboutViewModel = AboutViewModel(
|
||||
savedStateHandle = SavedStateHandle().apply { set("state", state) },
|
||||
clipboardManager = clipboardManager,
|
||||
)
|
||||
}
|
||||
|
||||
private val DEFAULT_ABOUT_STATE: AboutState = AboutState(
|
||||
version = "0".asText(),
|
||||
isSubmitCrashLogsEnabled = false,
|
||||
)
|
||||
|
|
|
@ -5,6 +5,7 @@ import app.cash.turbine.test
|
|||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedForwardedServiceUsernameResult
|
||||
import com.x8bit.bitwarden.data.tools.generator.repository.model.GeneratedPassphraseResult
|
||||
|
@ -14,7 +15,10 @@ import com.x8bit.bitwarden.data.tools.generator.repository.util.FakeGeneratorRep
|
|||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.runs
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
|
@ -65,6 +69,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
|
|||
every { userStateFlow } returns mutableUserStateFlow
|
||||
}
|
||||
|
||||
private val clipboardManager: BitwardenClipboardManager = mockk()
|
||||
private val fakeGeneratorRepository = FakeGeneratorRepository().apply {
|
||||
setMockGeneratePasswordResult(
|
||||
GeneratedPasswordResult.Success("defaultPassword"),
|
||||
|
@ -209,11 +214,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
|
|||
@Test
|
||||
fun `RegenerateClick for plus addressed email state should update the plus addressed email correctly`() =
|
||||
runTest {
|
||||
val viewModel = GeneratorViewModel(
|
||||
usernameSavedStateHandle,
|
||||
fakeGeneratorRepository,
|
||||
authRepository,
|
||||
)
|
||||
val viewModel = createViewModel(usernameSavedStateHandle)
|
||||
|
||||
fakeGeneratorRepository.setMockGeneratePasswordResult(
|
||||
GeneratedPasswordResult.Success("DifferentUsername"),
|
||||
|
@ -235,13 +236,14 @@ class GeneratorViewModelTest : BaseViewModelTest() {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `CopyClick should emit CopyTextToClipboard event`() = runTest {
|
||||
fun `CopyClick should call setText on ClipboardManager`() {
|
||||
val viewModel = createViewModel()
|
||||
every { clipboardManager.setText(viewModel.stateFlow.value.generatedText) } just runs
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.actionChannel.trySend(GeneratorAction.CopyClick)
|
||||
viewModel.actionChannel.trySend(GeneratorAction.CopyClick)
|
||||
|
||||
assertEquals(GeneratorEvent.CopyTextToClipboard, awaitItem())
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(text = viewModel.stateFlow.value.generatedText)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -451,11 +453,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
|
|||
fakeGeneratorRepository.setMockGeneratePasswordResult(
|
||||
GeneratedPasswordResult.Success("defaultPassword"),
|
||||
)
|
||||
viewModel = GeneratorViewModel(
|
||||
initialPasscodeSavedStateHandle,
|
||||
fakeGeneratorRepository,
|
||||
authRepository,
|
||||
)
|
||||
viewModel = createViewModel(initialPasscodeSavedStateHandle)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
|
@ -828,11 +826,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
|
|||
fakeGeneratorRepository.setMockGeneratePasswordResult(
|
||||
GeneratedPasswordResult.Success("defaultPassphrase"),
|
||||
)
|
||||
viewModel = GeneratorViewModel(
|
||||
passphraseSavedStateHandle,
|
||||
fakeGeneratorRepository,
|
||||
authRepository,
|
||||
)
|
||||
viewModel = createViewModel(passphraseSavedStateHandle)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -969,12 +963,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
|
|||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
viewModel =
|
||||
GeneratorViewModel(
|
||||
forwardedEmailAliasSavedStateHandle,
|
||||
fakeGeneratorRepository,
|
||||
authRepository,
|
||||
)
|
||||
viewModel = createViewModel(forwardedEmailAliasSavedStateHandle)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1031,11 +1020,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
|
|||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
viewModel = GeneratorViewModel(
|
||||
addyIoSavedStateHandle,
|
||||
fakeGeneratorRepository,
|
||||
authRepository,
|
||||
)
|
||||
viewModel = createViewModel(addyIoSavedStateHandle)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1125,11 +1110,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
|
|||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
viewModel = GeneratorViewModel(
|
||||
duckDuckGoSavedStateHandle,
|
||||
fakeGeneratorRepository,
|
||||
authRepository,
|
||||
)
|
||||
viewModel = createViewModel(duckDuckGoSavedStateHandle)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1179,11 +1160,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
|
|||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
viewModel = GeneratorViewModel(
|
||||
fastMailSavedStateHandle,
|
||||
fakeGeneratorRepository,
|
||||
authRepository,
|
||||
)
|
||||
viewModel = createViewModel(fastMailSavedStateHandle)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1233,11 +1210,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
|
|||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
viewModel = GeneratorViewModel(
|
||||
firefoxRelaySavedStateHandle,
|
||||
fakeGeneratorRepository,
|
||||
authRepository,
|
||||
)
|
||||
viewModel = createViewModel(firefoxRelaySavedStateHandle)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1288,11 +1261,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
|
|||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
viewModel = GeneratorViewModel(
|
||||
simpleLoginSavedStateHandle,
|
||||
fakeGeneratorRepository,
|
||||
authRepository,
|
||||
)
|
||||
viewModel = createViewModel(simpleLoginSavedStateHandle)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1343,11 +1312,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
|
|||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
viewModel = GeneratorViewModel(
|
||||
usernameSavedStateHandle,
|
||||
fakeGeneratorRepository,
|
||||
authRepository,
|
||||
)
|
||||
viewModel = createViewModel(usernameSavedStateHandle)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
|
@ -1390,11 +1355,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
|
|||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
viewModel = GeneratorViewModel(
|
||||
catchAllEmailSavedStateHandle,
|
||||
fakeGeneratorRepository,
|
||||
authRepository,
|
||||
)
|
||||
viewModel = createViewModel(catchAllEmailSavedStateHandle)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
|
@ -1436,11 +1397,7 @@ class GeneratorViewModelTest : BaseViewModelTest() {
|
|||
|
||||
@BeforeEach
|
||||
fun setup() {
|
||||
viewModel = GeneratorViewModel(
|
||||
randomWordSavedStateHandle,
|
||||
fakeGeneratorRepository,
|
||||
authRepository,
|
||||
)
|
||||
viewModel = createViewModel(randomWordSavedStateHandle)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
|
@ -1704,13 +1661,20 @@ class GeneratorViewModelTest : BaseViewModelTest() {
|
|||
}
|
||||
|
||||
private fun createViewModel(
|
||||
state: GeneratorState? = initialPasscodeState,
|
||||
savedStateHandle: SavedStateHandle,
|
||||
): GeneratorViewModel = GeneratorViewModel(
|
||||
savedStateHandle = SavedStateHandle().apply { set("state", state) },
|
||||
savedStateHandle = savedStateHandle,
|
||||
clipboardManager = clipboardManager,
|
||||
generatorRepository = fakeGeneratorRepository,
|
||||
authRepository = authRepository,
|
||||
)
|
||||
|
||||
private fun createViewModel(
|
||||
state: GeneratorState? = initialPasscodeState,
|
||||
): GeneratorViewModel = createViewModel(
|
||||
savedStateHandle = SavedStateHandle().apply { set("state", state) },
|
||||
)
|
||||
|
||||
//endregion Helper Functions
|
||||
}
|
||||
|
||||
|
|
|
@ -3,11 +3,17 @@ package com.x8bit.bitwarden.ui.tools.feature.generator.passwordhistory
|
|||
import app.cash.turbine.test
|
||||
import com.bitwarden.core.PasswordHistoryView
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.LocalDataState
|
||||
import com.x8bit.bitwarden.data.tools.generator.repository.util.FakeGeneratorRepository
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.tools.feature.generator.util.toFormattedPattern
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.runs
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
|
@ -18,6 +24,9 @@ class PasswordHistoryViewModelTest : BaseViewModelTest() {
|
|||
|
||||
private val initialState = PasswordHistoryState(PasswordHistoryState.ViewState.Loading)
|
||||
|
||||
private val clipboardManager: BitwardenClipboardManager = mockk()
|
||||
private val fakeGeneratorRepository = FakeGeneratorRepository()
|
||||
|
||||
@Test
|
||||
fun `initial state should be correct`() = runTest {
|
||||
val viewModel = createViewModel()
|
||||
|
@ -28,10 +37,8 @@ class PasswordHistoryViewModelTest : BaseViewModelTest() {
|
|||
|
||||
@Test
|
||||
fun `when repository emits Loading state the state updates correctly`() = runTest {
|
||||
val fakeRepository = FakeGeneratorRepository().apply {
|
||||
emitPasswordHistoryState(LocalDataState.Loading)
|
||||
}
|
||||
val viewModel = PasswordHistoryViewModel(generatorRepository = fakeRepository)
|
||||
fakeGeneratorRepository.emitPasswordHistoryState(LocalDataState.Loading)
|
||||
val viewModel = createViewModel()
|
||||
|
||||
viewModel.stateFlow.test {
|
||||
val expectedState = PasswordHistoryState(PasswordHistoryState.ViewState.Loading)
|
||||
|
@ -42,10 +49,10 @@ class PasswordHistoryViewModelTest : BaseViewModelTest() {
|
|||
|
||||
@Test
|
||||
fun `when repository emits Error state the state updates correctly`() = runTest {
|
||||
val fakeRepository = FakeGeneratorRepository().apply {
|
||||
emitPasswordHistoryState(LocalDataState.Error(Exception("An error has occurred.")))
|
||||
}
|
||||
val viewModel = PasswordHistoryViewModel(generatorRepository = fakeRepository)
|
||||
fakeGeneratorRepository.emitPasswordHistoryState(
|
||||
state = LocalDataState.Error(Exception("An error has occurred.")),
|
||||
)
|
||||
val viewModel = createViewModel()
|
||||
|
||||
viewModel.stateFlow.test {
|
||||
val expectedState = PasswordHistoryState(
|
||||
|
@ -58,10 +65,8 @@ class PasswordHistoryViewModelTest : BaseViewModelTest() {
|
|||
|
||||
@Test
|
||||
fun `when repository emits Empty state the state updates correctly`() = runTest {
|
||||
val fakeRepository = FakeGeneratorRepository().apply {
|
||||
emitPasswordHistoryState(LocalDataState.Loaded(emptyList()))
|
||||
}
|
||||
val viewModel = PasswordHistoryViewModel(generatorRepository = fakeRepository)
|
||||
fakeGeneratorRepository.emitPasswordHistoryState(LocalDataState.Loaded(emptyList()))
|
||||
val viewModel = createViewModel()
|
||||
|
||||
viewModel.stateFlow.test {
|
||||
val expectedState = PasswordHistoryState(PasswordHistoryState.ViewState.Empty)
|
||||
|
@ -72,11 +77,10 @@ class PasswordHistoryViewModelTest : BaseViewModelTest() {
|
|||
|
||||
@Test
|
||||
fun `when password history updates the state updates correctly`() = runTest {
|
||||
val fakeRepository = FakeGeneratorRepository()
|
||||
val viewModel = PasswordHistoryViewModel(generatorRepository = fakeRepository)
|
||||
val viewModel = createViewModel()
|
||||
|
||||
val passwordHistoryView = PasswordHistoryView("password", Instant.now())
|
||||
fakeRepository.storePasswordHistory(passwordHistoryView)
|
||||
fakeGeneratorRepository.storePasswordHistory(passwordHistoryView)
|
||||
|
||||
val expectedState = PasswordHistoryState(
|
||||
viewState = PasswordHistoryState.ViewState.Content(
|
||||
|
@ -108,45 +112,44 @@ class PasswordHistoryViewModelTest : BaseViewModelTest() {
|
|||
}
|
||||
|
||||
@Test
|
||||
fun `PasswordCopyClick action should emit CopyTextToClipboard event`() = runTest {
|
||||
fun `PasswordCopyClick action should call setText on the ClipboardManager`() {
|
||||
val viewModel = createViewModel()
|
||||
val generatedPassword = PasswordHistoryState.GeneratedPassword(
|
||||
password = "testPassword",
|
||||
date = "01/01/23",
|
||||
)
|
||||
every { clipboardManager.setText(text = generatedPassword.password) } just runs
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.actionChannel.trySend(
|
||||
PasswordHistoryAction.PasswordCopyClick(generatedPassword),
|
||||
)
|
||||
assertEquals(
|
||||
PasswordHistoryEvent.CopyTextToClipboard(generatedPassword.password),
|
||||
awaitItem(),
|
||||
)
|
||||
viewModel.actionChannel.trySend(PasswordHistoryAction.PasswordCopyClick(generatedPassword))
|
||||
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(text = generatedPassword.password)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `PasswordClearClick action should update to Empty ViewState`() = runTest {
|
||||
val fakeRepository = FakeGeneratorRepository()
|
||||
val viewModel = PasswordHistoryViewModel(generatorRepository = fakeRepository)
|
||||
val viewModel = createViewModel()
|
||||
|
||||
val passwordHistoryView = PasswordHistoryView("password", Instant.now())
|
||||
fakeRepository.storePasswordHistory(passwordHistoryView)
|
||||
fakeGeneratorRepository.storePasswordHistory(passwordHistoryView)
|
||||
|
||||
viewModel.actionChannel.trySend(PasswordHistoryAction.PasswordClearClick)
|
||||
|
||||
assertTrue(fakeRepository.passwordHistoryStateFlow.value is LocalDataState.Loaded)
|
||||
assertTrue(fakeGeneratorRepository.passwordHistoryStateFlow.value is LocalDataState.Loaded)
|
||||
assertTrue(
|
||||
(fakeRepository.passwordHistoryStateFlow.value as LocalDataState.Loaded).data.isEmpty(),
|
||||
(fakeGeneratorRepository.passwordHistoryStateFlow.value as LocalDataState.Loaded)
|
||||
.data
|
||||
.isEmpty(),
|
||||
)
|
||||
}
|
||||
|
||||
//region Helper Functions
|
||||
|
||||
private fun createViewModel(): PasswordHistoryViewModel {
|
||||
return PasswordHistoryViewModel(generatorRepository = FakeGeneratorRepository())
|
||||
}
|
||||
private fun createViewModel(): PasswordHistoryViewModel = PasswordHistoryViewModel(
|
||||
clipboardManager = clipboardManager,
|
||||
generatorRepository = fakeGeneratorRepository,
|
||||
)
|
||||
|
||||
//endregion Helper Functions
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.x8bit.bitwarden.ui.tools.feature.send
|
||||
|
||||
import androidx.compose.ui.platform.ClipboardManager
|
||||
import androidx.compose.ui.test.assert
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertTextEquals
|
||||
|
@ -23,7 +22,6 @@ import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFl
|
|||
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.IntentHandler
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.toAnnotatedString
|
||||
import com.x8bit.bitwarden.ui.util.assertNoDialogExists
|
||||
import com.x8bit.bitwarden.ui.util.isProgressBar
|
||||
import io.mockk.every
|
||||
|
@ -41,9 +39,6 @@ class SendScreenTest : BaseComposeTest() {
|
|||
|
||||
private var onNavigateToNewSendCalled = false
|
||||
|
||||
private val clipboardManager = mockk<ClipboardManager> {
|
||||
every { setText(any()) } just runs
|
||||
}
|
||||
private val intentHandler = mockk<IntentHandler> {
|
||||
every { launchUri(any()) } just runs
|
||||
}
|
||||
|
@ -60,21 +55,11 @@ class SendScreenTest : BaseComposeTest() {
|
|||
SendScreen(
|
||||
viewModel = viewModel,
|
||||
onNavigateToAddSend = { onNavigateToNewSendCalled = true },
|
||||
clipboardManager = clipboardManager,
|
||||
intentHandler = intentHandler,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on CopyToClipboard should call setText on the clipboardManager`() {
|
||||
val text = "copy text"
|
||||
mutableEventFlow.tryEmit(SendEvent.CopyToClipboard(text.asText()))
|
||||
verify {
|
||||
clipboardManager.setText(text.toAnnotatedString())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on NavigateToNewSend should call onNavigateToNewSend`() {
|
||||
mutableEventFlow.tryEmit(SendEvent.NavigateNewSend)
|
||||
|
|
|
@ -3,6 +3,7 @@ package com.x8bit.bitwarden.ui.tools.feature.send
|
|||
import androidx.lifecycle.SavedStateHandle
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.DataState
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.SendData
|
||||
|
@ -27,6 +28,8 @@ import org.junit.jupiter.api.Test
|
|||
class SendViewModelTest : BaseViewModelTest() {
|
||||
|
||||
private val mutableSendDataFlow = MutableStateFlow<DataState<SendData>>(DataState.Loading)
|
||||
|
||||
private val clipboardManager: BitwardenClipboardManager = mockk()
|
||||
private val vaultRepo: VaultRepository = mockk {
|
||||
every { sendDataStateFlow } returns mutableSendDataFlow
|
||||
}
|
||||
|
@ -232,11 +235,13 @@ class SendViewModelTest : BaseViewModelTest() {
|
|||
|
||||
private fun createViewModel(
|
||||
state: SendState? = null,
|
||||
bitwardenClipboardManager: BitwardenClipboardManager = clipboardManager,
|
||||
vaultRepository: VaultRepository = vaultRepo,
|
||||
): SendViewModel = SendViewModel(
|
||||
savedStateHandle = SavedStateHandle().apply {
|
||||
set("state", state)
|
||||
},
|
||||
clipboardManager = bitwardenClipboardManager,
|
||||
vaultRepo = vaultRepository,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package com.x8bit.bitwarden.ui.vault.feature.addedit
|
||||
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.platform.ClipboardManager
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertIsEnabled
|
||||
import androidx.compose.ui.test.assertIsNotDisplayed
|
||||
|
@ -32,7 +31,6 @@ import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFl
|
|||
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.FakePermissionManager
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.toAnnotatedString
|
||||
import com.x8bit.bitwarden.ui.util.isProgressBar
|
||||
import com.x8bit.bitwarden.ui.util.onAllNodesWithTextAfterScroll
|
||||
import com.x8bit.bitwarden.ui.util.onNodeWithContentDescriptionAfterScroll
|
||||
|
@ -43,9 +41,7 @@ import com.x8bit.bitwarden.ui.vault.model.VaultCardBrand
|
|||
import com.x8bit.bitwarden.ui.vault.model.VaultCardExpirationMonth
|
||||
import com.x8bit.bitwarden.ui.vault.model.VaultIdentityTitle
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.runs
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.update
|
||||
|
@ -59,8 +55,6 @@ class VaultAddEditScreenTest : BaseComposeTest() {
|
|||
private var onNavigateBackCalled = false
|
||||
private var onNavigateQrCodeScanScreenCalled = false
|
||||
|
||||
private val clipboardManager = mockk<ClipboardManager>()
|
||||
|
||||
private val mutableEventFlow = bufferedMutableSharedFlow<VaultAddEditEvent>()
|
||||
private val mutableStateFlow = MutableStateFlow(DEFAULT_STATE_LOGIN)
|
||||
|
||||
|
@ -78,7 +72,6 @@ class VaultAddEditScreenTest : BaseComposeTest() {
|
|||
viewModel = viewModel,
|
||||
onNavigateBack = { onNavigateBackCalled = true },
|
||||
permissionsManager = fakePermissionManager,
|
||||
clipboardManager = clipboardManager,
|
||||
onNavigateToQrCodeScanScreen = {
|
||||
onNavigateQrCodeScanScreenCalled = true
|
||||
},
|
||||
|
@ -99,19 +92,6 @@ class VaultAddEditScreenTest : BaseComposeTest() {
|
|||
assertTrue(onNavigateQrCodeScanScreenCalled)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on CopyToClipboard should call setText on ClipboardManager`() {
|
||||
val textString = "text"
|
||||
|
||||
every { clipboardManager.setText(textString.toAnnotatedString()) } just runs
|
||||
|
||||
mutableEventFlow.tryEmit(VaultAddEditEvent.CopyToClipboard(textString))
|
||||
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(textString.toAnnotatedString())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `clicking close button should send CloseClick action`() {
|
||||
composeTestRule
|
||||
|
|
|
@ -4,6 +4,7 @@ import androidx.lifecycle.SavedStateHandle
|
|||
import app.cash.turbine.test
|
||||
import com.bitwarden.core.CipherView
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.DataState
|
||||
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
|
@ -23,8 +24,10 @@ import com.x8bit.bitwarden.ui.vault.model.VaultLinkedFieldType
|
|||
import io.mockk.coEvery
|
||||
import io.mockk.coVerify
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
import io.mockk.runs
|
||||
import io.mockk.unmockkStatic
|
||||
import io.mockk.verify
|
||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||
|
@ -50,6 +53,8 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
|||
private val totpTestCodeFlow: MutableSharedFlow<String> = bufferedMutableSharedFlow()
|
||||
|
||||
private val mutableVaultItemFlow = MutableStateFlow<DataState<CipherView?>>(DataState.Loading)
|
||||
|
||||
private val clipboardManager: BitwardenClipboardManager = mockk()
|
||||
private val vaultRepository: VaultRepository = mockk {
|
||||
every { getVaultItemStateFlow(DEFAULT_EDIT_ITEM_ID) } returns mutableVaultItemFlow
|
||||
every { totpCodeFlow } returns totpTestCodeFlow
|
||||
|
@ -570,23 +575,20 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `CopyTotpKeyClick should emit a toast and CopyToClipboard`() = runTest {
|
||||
fun `CopyTotpKeyClick should call setText on ClipboardManager`() {
|
||||
val viewModel = createAddVaultItemViewModel()
|
||||
val testKey = "TestKey"
|
||||
every { clipboardManager.setText(text = testKey) } just runs
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.actionChannel.trySend(
|
||||
VaultAddEditAction.ItemType.LoginType.CopyTotpKeyClick(
|
||||
testKey,
|
||||
),
|
||||
)
|
||||
viewModel.actionChannel.trySend(
|
||||
VaultAddEditAction.ItemType.LoginType.CopyTotpKeyClick(
|
||||
testKey,
|
||||
),
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
VaultAddEditEvent.CopyToClipboard(testKey),
|
||||
awaitItem(),
|
||||
)
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(text = testKey)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1068,6 +1070,7 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
|||
)
|
||||
viewModel = VaultAddEditViewModel(
|
||||
savedStateHandle = secureNotesInitialSavedStateHandle,
|
||||
clipboardManager = clipboardManager,
|
||||
vaultRepository = vaultRepository,
|
||||
)
|
||||
}
|
||||
|
@ -1368,10 +1371,12 @@ class VaultAddEditViewModelTest : BaseViewModelTest() {
|
|||
|
||||
private fun createAddVaultItemViewModel(
|
||||
savedStateHandle: SavedStateHandle = loginInitialSavedStateHandle,
|
||||
bitwardenClipboardManager: BitwardenClipboardManager = clipboardManager,
|
||||
vaultRepo: VaultRepository = vaultRepository,
|
||||
): VaultAddEditViewModel =
|
||||
VaultAddEditViewModel(
|
||||
savedStateHandle = savedStateHandle,
|
||||
clipboardManager = bitwardenClipboardManager,
|
||||
vaultRepository = vaultRepo,
|
||||
)
|
||||
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package com.x8bit.bitwarden.ui.vault.feature.item
|
||||
|
||||
import androidx.compose.ui.platform.ClipboardManager
|
||||
import androidx.compose.ui.test.assert
|
||||
import androidx.compose.ui.test.assertIsDisplayed
|
||||
import androidx.compose.ui.test.assertIsEnabled
|
||||
|
@ -23,7 +22,6 @@ import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFl
|
|||
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.IntentHandler
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.toAnnotatedString
|
||||
import com.x8bit.bitwarden.ui.util.assertScrollableNodeDoesNotExist
|
||||
import com.x8bit.bitwarden.ui.util.isProgressBar
|
||||
import com.x8bit.bitwarden.ui.util.onFirstNodeWithTextAfterScroll
|
||||
|
@ -47,7 +45,6 @@ class VaultItemScreenTest : BaseComposeTest() {
|
|||
private var onNavigateBackCalled = false
|
||||
private var onNavigateToVaultEditItemId: String? = null
|
||||
|
||||
private val clipboardManager = mockk<ClipboardManager>()
|
||||
private val intentHandler = mockk<IntentHandler>()
|
||||
|
||||
private val mutableEventFlow = bufferedMutableSharedFlow<VaultItemEvent>()
|
||||
|
@ -64,7 +61,6 @@ class VaultItemScreenTest : BaseComposeTest() {
|
|||
viewModel = viewModel,
|
||||
onNavigateBack = { onNavigateBackCalled = true },
|
||||
onNavigateToVaultEditItem = { onNavigateToVaultEditItemId = it },
|
||||
clipboardManager = clipboardManager,
|
||||
intentHandler = intentHandler,
|
||||
)
|
||||
}
|
||||
|
@ -86,19 +82,6 @@ class VaultItemScreenTest : BaseComposeTest() {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `CopyToClipboard event should invoke setText`() {
|
||||
val textString = "text"
|
||||
val text = textString.asText()
|
||||
every { clipboardManager.setText(textString.toAnnotatedString()) } just runs
|
||||
|
||||
mutableEventFlow.tryEmit(VaultItemEvent.CopyToClipboard(text))
|
||||
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(textString.toAnnotatedString())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `NavigateBack event should invoke onNavigateBack`() {
|
||||
mutableEventFlow.tryEmit(VaultItemEvent.NavigateBack)
|
||||
|
|
|
@ -7,6 +7,7 @@ import com.x8bit.bitwarden.R
|
|||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.BreachCountResult
|
||||
import com.x8bit.bitwarden.data.auth.repository.model.UserState
|
||||
import com.x8bit.bitwarden.data.platform.manager.clipboard.BitwardenClipboardManager
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.DataState
|
||||
import com.x8bit.bitwarden.data.platform.repository.model.Environment
|
||||
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
|
||||
|
@ -38,6 +39,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
|
|||
private val mutableVaultItemFlow = MutableStateFlow<DataState<CipherView?>>(DataState.Loading)
|
||||
private val mutableUserStateFlow = MutableStateFlow<UserState?>(DEFAULT_USER_STATE)
|
||||
|
||||
private val clipboardManager: BitwardenClipboardManager = mockk()
|
||||
private val authRepo: AuthRepository = mockk {
|
||||
every { userStateFlow } returns mutableUserStateFlow
|
||||
}
|
||||
|
@ -216,40 +218,33 @@ class VaultItemViewModelTest : BaseViewModelTest() {
|
|||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `on CopyCustomHiddenFieldClick should emit CopyToClipboard when re-prompt is not required`() =
|
||||
runTest {
|
||||
val field = "field"
|
||||
val mockCipherView = mockk<CipherView> {
|
||||
every {
|
||||
toViewState(isPremiumUser = true)
|
||||
}
|
||||
.returns(
|
||||
createViewState(
|
||||
common = DEFAULT_COMMON.copy(requiresReprompt = false),
|
||||
),
|
||||
)
|
||||
}
|
||||
mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView)
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(VaultItemAction.Common.CopyCustomHiddenFieldClick(field))
|
||||
assertEquals(
|
||||
VaultItemEvent.CopyToClipboard(field.asText()),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
|
||||
verify(exactly = 1) {
|
||||
mockCipherView.toViewState(isPremiumUser = true)
|
||||
}
|
||||
fun `on CopyCustomHiddenFieldClick should call setText on ClipboardManager when re-prompt is not required`() {
|
||||
val field = "field"
|
||||
val mockCipherView = mockk<CipherView> {
|
||||
every {
|
||||
toViewState(isPremiumUser = true)
|
||||
} returns createViewState(common = DEFAULT_COMMON.copy(requiresReprompt = false))
|
||||
}
|
||||
every { clipboardManager.setText(text = field) } just runs
|
||||
mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView)
|
||||
|
||||
viewModel.trySendAction(VaultItemAction.Common.CopyCustomHiddenFieldClick(field))
|
||||
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(text = field)
|
||||
mockCipherView.toViewState(isPremiumUser = true)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on CopyCustomTextFieldClick should emit CopyToClipboard`() = runTest {
|
||||
fun `on CopyCustomTextFieldClick should call setText on ClipboardManager`() {
|
||||
val field = "field"
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(VaultItemAction.Common.CopyCustomTextFieldClick(field))
|
||||
assertEquals(VaultItemEvent.CopyToClipboard(field.asText()), awaitItem())
|
||||
every { clipboardManager.setText(text = field) } just runs
|
||||
|
||||
viewModel.trySendAction(VaultItemAction.Common.CopyCustomTextFieldClick(field))
|
||||
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(text = field)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -402,41 +397,33 @@ class VaultItemViewModelTest : BaseViewModelTest() {
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `on CopyPasswordClick should emit CopyToClipboard when re-prompt is not required`() =
|
||||
runTest {
|
||||
val mockCipherView = mockk<CipherView> {
|
||||
every {
|
||||
toViewState(isPremiumUser = true)
|
||||
}
|
||||
.returns(
|
||||
createViewState(
|
||||
common = DEFAULT_COMMON.copy(requiresReprompt = false),
|
||||
),
|
||||
)
|
||||
}
|
||||
mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView)
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(VaultItemAction.ItemType.Login.CopyPasswordClick)
|
||||
assertEquals(
|
||||
VaultItemEvent.CopyToClipboard(DEFAULT_LOGIN_PASSWORD.asText()),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
|
||||
verify(exactly = 1) {
|
||||
mockCipherView.toViewState(isPremiumUser = true)
|
||||
}
|
||||
fun `on CopyPasswordClick should call setText on the CLipboardManager when re-prompt is not required`() {
|
||||
val mockCipherView = mockk<CipherView> {
|
||||
every {
|
||||
toViewState(isPremiumUser = true)
|
||||
} returns createViewState(common = DEFAULT_COMMON.copy(requiresReprompt = false))
|
||||
}
|
||||
every { clipboardManager.setText(text = DEFAULT_LOGIN_PASSWORD) } just runs
|
||||
mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView)
|
||||
|
||||
viewModel.trySendAction(VaultItemAction.ItemType.Login.CopyPasswordClick)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(text = DEFAULT_LOGIN_PASSWORD)
|
||||
mockCipherView.toViewState(isPremiumUser = true)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on CopyUriClick should emit CopyToClipboard`() = runTest {
|
||||
fun `on CopyUriClick should call setText on ClipboardManager`() {
|
||||
val uri = "uri"
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(VaultItemAction.ItemType.Login.CopyUriClick(uri))
|
||||
assertEquals(VaultItemEvent.CopyToClipboard(uri.asText()), awaitItem())
|
||||
}
|
||||
every { clipboardManager.setText(text = uri) } just runs
|
||||
|
||||
viewModel.trySendAction(VaultItemAction.ItemType.Login.CopyUriClick(uri))
|
||||
|
||||
verify(exactly = 1) { clipboardManager.setText(text = uri) }
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -460,33 +447,24 @@ class VaultItemViewModelTest : BaseViewModelTest() {
|
|||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `on CopyUsernameClick should emit CopyToClipboard when re-prompt is not required`() =
|
||||
runTest {
|
||||
val mockCipherView = mockk<CipherView> {
|
||||
every {
|
||||
toViewState(isPremiumUser = true)
|
||||
}
|
||||
.returns(
|
||||
createViewState(
|
||||
common = DEFAULT_COMMON.copy(requiresReprompt = false),
|
||||
),
|
||||
)
|
||||
}
|
||||
mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView)
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(VaultItemAction.ItemType.Login.CopyUsernameClick)
|
||||
assertEquals(
|
||||
VaultItemEvent.CopyToClipboard(DEFAULT_LOGIN_USERNAME.asText()),
|
||||
awaitItem(),
|
||||
)
|
||||
}
|
||||
|
||||
verify(exactly = 1) {
|
||||
mockCipherView.toViewState(isPremiumUser = true)
|
||||
}
|
||||
fun `on CopyUsernameClick should call setText on ClipboardManager when re-prompt is not required`() {
|
||||
val mockCipherView = mockk<CipherView> {
|
||||
every {
|
||||
toViewState(isPremiumUser = true)
|
||||
} returns createViewState(common = DEFAULT_COMMON.copy(requiresReprompt = false))
|
||||
}
|
||||
every { clipboardManager.setText(text = DEFAULT_LOGIN_USERNAME) } just runs
|
||||
mutableVaultItemFlow.value = DataState.Loaded(data = mockCipherView)
|
||||
|
||||
viewModel.trySendAction(VaultItemAction.ItemType.Login.CopyUsernameClick)
|
||||
|
||||
verify(exactly = 1) {
|
||||
clipboardManager.setText(text = DEFAULT_LOGIN_USERNAME)
|
||||
mockCipherView.toViewState(isPremiumUser = true)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on LaunchClick should emit NavigateToUri`() = runTest {
|
||||
|
@ -613,6 +591,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
|
|||
private fun createViewModel(
|
||||
state: VaultItemState?,
|
||||
vaultItemId: String = VAULT_ITEM_ID,
|
||||
bitwardenClipboardManager: BitwardenClipboardManager = clipboardManager,
|
||||
authRepository: AuthRepository = authRepo,
|
||||
vaultRepository: VaultRepository = vaultRepo,
|
||||
): VaultItemViewModel = VaultItemViewModel(
|
||||
|
@ -620,6 +599,7 @@ class VaultItemViewModelTest : BaseViewModelTest() {
|
|||
set("state", state)
|
||||
set("vault_item_id", vaultItemId)
|
||||
},
|
||||
clipboardManager = bitwardenClipboardManager,
|
||||
authRepository = authRepository,
|
||||
vaultRepository = vaultRepository,
|
||||
)
|
||||
|
|
Loading…
Add table
Reference in a new issue