mirror of
https://github.com/bitwarden/android.git
synced 2024-11-24 10:25:57 +03:00
BIT-2293, BIT-2294: Add vault and generator shortcuts (#1306)
This commit is contained in:
parent
80f6011571
commit
bb1fd4ae4f
13 changed files with 336 additions and 11 deletions
|
@ -33,6 +33,11 @@
|
|||
android:launchMode="@integer/launchModeAPIlevel"
|
||||
android:theme="@style/LaunchTheme"
|
||||
android:windowSoftInputMode="adjustResize">
|
||||
|
||||
<meta-data
|
||||
android:name="android.app.shortcuts"
|
||||
android:resource="@xml/shortcuts" />
|
||||
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@ import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
|||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppTheme
|
||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||
import com.x8bit.bitwarden.ui.platform.util.isMyVaultShortcut
|
||||
import com.x8bit.bitwarden.ui.platform.util.isPasswordGeneratorShortcut
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
|
@ -116,6 +118,8 @@ class MainViewModel @Inject constructor(
|
|||
val autofillSaveItem = intent.getAutofillSaveItemOrNull()
|
||||
val autofillSelectionData = intent.getAutofillSelectionDataOrNull()
|
||||
val shareData = intentManager.getShareDataFromIntent(intent)
|
||||
val hasGeneratorShortcut = intent.isPasswordGeneratorShortcut
|
||||
val hasVaultShortcut = intent.isMyVaultShortcut
|
||||
when {
|
||||
passwordlessRequestData != null -> {
|
||||
specialCircumstanceManager.specialCircumstance =
|
||||
|
@ -153,6 +157,15 @@ class MainViewModel @Inject constructor(
|
|||
shouldFinishWhenComplete = isFirstIntent,
|
||||
)
|
||||
}
|
||||
|
||||
hasGeneratorShortcut -> {
|
||||
specialCircumstanceManager.specialCircumstance =
|
||||
SpecialCircumstance.GeneratorShortcut
|
||||
}
|
||||
|
||||
hasVaultShortcut -> {
|
||||
specialCircumstanceManager.specialCircumstance = SpecialCircumstance.VaultShortcut
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,4 +46,16 @@ sealed class SpecialCircumstance : Parcelable {
|
|||
val passwordlessRequestData: PasswordlessRequestData,
|
||||
val shouldFinishWhenComplete: Boolean,
|
||||
) : SpecialCircumstance()
|
||||
|
||||
/**
|
||||
* The app was launched via deeplink to the generator.
|
||||
*/
|
||||
@Parcelize
|
||||
data object GeneratorShortcut : SpecialCircumstance()
|
||||
|
||||
/**
|
||||
* The app was launched via deeplink to the vault.
|
||||
*/
|
||||
@Parcelize
|
||||
data object VaultShortcut : SpecialCircumstance()
|
||||
}
|
||||
|
|
|
@ -13,6 +13,8 @@ fun SpecialCircumstance.toAutofillSaveItemOrNull(): AutofillSaveItem? =
|
|||
is SpecialCircumstance.AutofillSelection -> null
|
||||
is SpecialCircumstance.PasswordlessRequest -> null
|
||||
is SpecialCircumstance.ShareNewSend -> null
|
||||
SpecialCircumstance.GeneratorShortcut -> null
|
||||
SpecialCircumstance.VaultShortcut -> null
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -24,4 +26,6 @@ fun SpecialCircumstance.toAutofillSelectionDataOrNull(): AutofillSelectionData?
|
|||
is SpecialCircumstance.AutofillSelection -> this.autofillSelectionData
|
||||
is SpecialCircumstance.PasswordlessRequest -> null
|
||||
is SpecialCircumstance.ShareNewSend -> null
|
||||
SpecialCircumstance.GeneratorShortcut -> null
|
||||
SpecialCircumstance.VaultShortcut -> null
|
||||
}
|
||||
|
|
|
@ -59,7 +59,6 @@ class RootNavViewModel @Inject constructor(
|
|||
action: RootNavAction.Internal.UserStateUpdateReceive,
|
||||
) {
|
||||
val userState = action.userState
|
||||
val specialCircumstance = action.specialCircumstance
|
||||
val updatedRootNavState = when {
|
||||
userState?.activeAccount?.trustedDevice?.isDeviceTrusted == false &&
|
||||
!userState.activeAccount.isVaultUnlocked -> RootNavState.TrustedDevice
|
||||
|
@ -73,7 +72,7 @@ class RootNavViewModel @Inject constructor(
|
|||
userState.hasPendingAccountAddition -> RootNavState.Auth
|
||||
|
||||
userState.activeAccount.isVaultUnlocked -> {
|
||||
when (specialCircumstance) {
|
||||
when (val specialCircumstance = action.specialCircumstance) {
|
||||
is SpecialCircumstance.AutofillSave -> {
|
||||
RootNavState.VaultUnlockedForAutofillSave(
|
||||
autofillSaveItem = specialCircumstance.autofillSaveItem,
|
||||
|
@ -93,11 +92,10 @@ class RootNavViewModel @Inject constructor(
|
|||
RootNavState.VaultUnlockedForAuthRequest
|
||||
}
|
||||
|
||||
null -> {
|
||||
RootNavState.VaultUnlocked(
|
||||
activeUserId = userState.activeAccount.userId,
|
||||
)
|
||||
}
|
||||
SpecialCircumstance.GeneratorShortcut,
|
||||
SpecialCircumstance.VaultShortcut,
|
||||
null,
|
||||
-> RootNavState.VaultUnlocked(activeUserId = userState.activeAccount.userId)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package com.x8bit.bitwarden.ui.platform.feature.vaultunlockednavbar
|
||||
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
import javax.inject.Inject
|
||||
|
@ -11,10 +13,25 @@ import javax.inject.Inject
|
|||
@HiltViewModel
|
||||
class VaultUnlockedNavBarViewModel @Inject constructor(
|
||||
private val authRepository: AuthRepository,
|
||||
) :
|
||||
BaseViewModel<Unit, VaultUnlockedNavBarEvent, VaultUnlockedNavBarAction>(
|
||||
initialState = Unit,
|
||||
) {
|
||||
specialCircumstancesManager: SpecialCircumstanceManager,
|
||||
) : BaseViewModel<Unit, VaultUnlockedNavBarEvent, VaultUnlockedNavBarAction>(
|
||||
initialState = Unit,
|
||||
) {
|
||||
init {
|
||||
when (specialCircumstancesManager.specialCircumstance) {
|
||||
SpecialCircumstance.GeneratorShortcut -> {
|
||||
sendEvent(VaultUnlockedNavBarEvent.NavigateToGeneratorScreen)
|
||||
specialCircumstancesManager.specialCircumstance = null
|
||||
}
|
||||
|
||||
SpecialCircumstance.VaultShortcut -> {
|
||||
sendEvent(VaultUnlockedNavBarEvent.NavigateToVaultScreen)
|
||||
specialCircumstancesManager.specialCircumstance = null
|
||||
}
|
||||
|
||||
else -> Unit
|
||||
}
|
||||
}
|
||||
|
||||
override fun handleAction(action: VaultUnlockedNavBarAction) {
|
||||
when (action) {
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
package com.x8bit.bitwarden.ui.platform.util
|
||||
|
||||
import android.content.Intent
|
||||
|
||||
/**
|
||||
* Returns `true` if the [Intent] is a deeplink to the vault, `false` otherwise.
|
||||
*/
|
||||
val Intent.isMyVaultShortcut: Boolean
|
||||
get() = dataString?.equals("bitwarden://my_vault") == true
|
||||
|
||||
/**
|
||||
* Returns `true` if the [Intent] is a deeplink to the password generator, `false` otherwise.
|
||||
*/
|
||||
val Intent.isPasswordGeneratorShortcut: Boolean
|
||||
get() = dataString?.equals("bitwarden://password_generator") == true
|
27
app/src/main/res/xml/shortcuts.xml
Normal file
27
app/src/main/res/xml/shortcuts.xml
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<shortcut
|
||||
android:enabled="true"
|
||||
android:icon="@drawable/ic_generator"
|
||||
android:shortcutId="bitwarden_password_generator"
|
||||
android:shortcutLongLabel="@string/password_generator"
|
||||
android:shortcutShortLabel="@string/password_generator">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="bitwarden://password_generator"
|
||||
android:targetClass="com.x8bit.bitwarden.MainActivity"
|
||||
android:targetPackage="com.x8bit.bitwarden.dev" />
|
||||
</shortcut>
|
||||
<shortcut
|
||||
android:enabled="true"
|
||||
android:icon="@drawable/ic_vault"
|
||||
android:shortcutId="bitwarden_my_vault"
|
||||
android:shortcutLongLabel="@string/my_vault"
|
||||
android:shortcutShortLabel="@string/my_vault">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="bitwarden://my_vault"
|
||||
android:targetClass="com.x8bit.bitwarden.MainActivity"
|
||||
android:targetPackage="com.x8bit.bitwarden.dev" />
|
||||
</shortcut>
|
||||
</shortcuts>
|
27
app/src/release/res/xml/shortcuts.xml
Normal file
27
app/src/release/res/xml/shortcuts.xml
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shortcuts xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<shortcut
|
||||
android:enabled="true"
|
||||
android:icon="@drawable/ic_generator"
|
||||
android:shortcutId="bitwarden_password_generator"
|
||||
android:shortcutLongLabel="@string/password_generator"
|
||||
android:shortcutShortLabel="@string/password_generator">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="bitwarden://password_generator"
|
||||
android:targetClass="com.x8bit.bitwarden.MainActivity"
|
||||
android:targetPackage="com.x8bit.bitwarden" />
|
||||
</shortcut>
|
||||
<shortcut
|
||||
android:enabled="true"
|
||||
android:icon="@drawable/ic_vault"
|
||||
android:shortcutId="bitwarden_my_vault"
|
||||
android:shortcutLongLabel="@string/my_vault"
|
||||
android:shortcutShortLabel="@string/my_vault">
|
||||
<intent
|
||||
android:action="android.intent.action.VIEW"
|
||||
android:data="bitwarden://my_vault"
|
||||
android:targetClass="com.x8bit.bitwarden.MainActivity"
|
||||
android:targetPackage="com.x8bit.bitwarden" />
|
||||
</shortcut>
|
||||
</shortcuts>
|
|
@ -18,6 +18,8 @@ import com.x8bit.bitwarden.data.platform.repository.SettingsRepository
|
|||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import com.x8bit.bitwarden.ui.platform.feature.settings.appearance.model.AppTheme
|
||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||
import com.x8bit.bitwarden.ui.platform.util.isMyVaultShortcut
|
||||
import com.x8bit.bitwarden.ui.platform.util.isPasswordGeneratorShortcut
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import io.mockk.mockkStatic
|
||||
|
@ -54,6 +56,10 @@ class MainViewModelTest : BaseViewModelTest() {
|
|||
Intent::getAutofillSaveItemOrNull,
|
||||
Intent::getAutofillSelectionDataOrNull,
|
||||
)
|
||||
mockkStatic(
|
||||
Intent::isMyVaultShortcut,
|
||||
Intent::isPasswordGeneratorShortcut,
|
||||
)
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
|
@ -63,6 +69,10 @@ class MainViewModelTest : BaseViewModelTest() {
|
|||
Intent::getAutofillSaveItemOrNull,
|
||||
Intent::getAutofillSelectionDataOrNull,
|
||||
)
|
||||
unmockkStatic(
|
||||
Intent::isMyVaultShortcut,
|
||||
Intent::isPasswordGeneratorShortcut,
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
|
@ -150,6 +160,8 @@ class MainViewModelTest : BaseViewModelTest() {
|
|||
every { mockIntent.getAutofillSaveItemOrNull() } returns null
|
||||
every { mockIntent.getAutofillSelectionDataOrNull() } returns null
|
||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns shareData
|
||||
every { mockIntent.isMyVaultShortcut } returns false
|
||||
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
||||
|
||||
viewModel.trySendAction(
|
||||
MainAction.ReceiveFirstIntent(
|
||||
|
@ -175,6 +187,8 @@ class MainViewModelTest : BaseViewModelTest() {
|
|||
every { mockIntent.getAutofillSaveItemOrNull() } returns null
|
||||
every { mockIntent.getAutofillSelectionDataOrNull() } returns autofillSelectionData
|
||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||
every { mockIntent.isMyVaultShortcut } returns false
|
||||
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
||||
|
||||
viewModel.trySendAction(
|
||||
MainAction.ReceiveFirstIntent(
|
||||
|
@ -200,6 +214,8 @@ class MainViewModelTest : BaseViewModelTest() {
|
|||
every { mockIntent.getAutofillSaveItemOrNull() } returns autofillSaveItem
|
||||
every { mockIntent.getAutofillSelectionDataOrNull() } returns null
|
||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||
every { mockIntent.isMyVaultShortcut } returns false
|
||||
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
||||
|
||||
viewModel.trySendAction(
|
||||
MainAction.ReceiveFirstIntent(
|
||||
|
@ -226,6 +242,8 @@ class MainViewModelTest : BaseViewModelTest() {
|
|||
every { mockIntent.getAutofillSaveItemOrNull() } returns null
|
||||
every { mockIntent.getAutofillSelectionDataOrNull() } returns null
|
||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||
every { mockIntent.isMyVaultShortcut } returns false
|
||||
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
||||
|
||||
viewModel.trySendAction(
|
||||
MainAction.ReceiveFirstIntent(
|
||||
|
@ -251,6 +269,8 @@ class MainViewModelTest : BaseViewModelTest() {
|
|||
every { mockIntent.getAutofillSaveItemOrNull() } returns null
|
||||
every { mockIntent.getAutofillSelectionDataOrNull() } returns null
|
||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns shareData
|
||||
every { mockIntent.isMyVaultShortcut } returns false
|
||||
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
||||
|
||||
viewModel.trySendAction(
|
||||
MainAction.ReceiveNewIntent(
|
||||
|
@ -276,6 +296,8 @@ class MainViewModelTest : BaseViewModelTest() {
|
|||
every { mockIntent.getAutofillSaveItemOrNull() } returns null
|
||||
every { mockIntent.getAutofillSelectionDataOrNull() } returns autofillSelectionData
|
||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||
every { mockIntent.isMyVaultShortcut } returns false
|
||||
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
||||
|
||||
viewModel.trySendAction(
|
||||
MainAction.ReceiveNewIntent(
|
||||
|
@ -301,6 +323,8 @@ class MainViewModelTest : BaseViewModelTest() {
|
|||
every { mockIntent.getAutofillSaveItemOrNull() } returns autofillSaveItem
|
||||
every { mockIntent.getAutofillSelectionDataOrNull() } returns null
|
||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||
every { mockIntent.isMyVaultShortcut } returns false
|
||||
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
||||
|
||||
viewModel.trySendAction(
|
||||
MainAction.ReceiveNewIntent(
|
||||
|
@ -327,6 +351,8 @@ class MainViewModelTest : BaseViewModelTest() {
|
|||
every { mockIntent.getAutofillSaveItemOrNull() } returns null
|
||||
every { mockIntent.getAutofillSelectionDataOrNull() } returns null
|
||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||
every { mockIntent.isMyVaultShortcut } returns false
|
||||
every { mockIntent.isPasswordGeneratorShortcut } returns false
|
||||
|
||||
viewModel.trySendAction(
|
||||
MainAction.ReceiveNewIntent(
|
||||
|
@ -342,6 +368,54 @@ class MainViewModelTest : BaseViewModelTest() {
|
|||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `on ReceiveNewIntent with a Vault deeplink data should set the special circumstance to VaultShortcut`() {
|
||||
val viewModel = createViewModel()
|
||||
val mockIntent = mockk<Intent> {
|
||||
every { getPasswordlessRequestDataIntentOrNull() } returns null
|
||||
every { getAutofillSaveItemOrNull() } returns null
|
||||
every { getAutofillSelectionDataOrNull() } returns null
|
||||
every { isMyVaultShortcut } returns true
|
||||
every { isPasswordGeneratorShortcut } returns false
|
||||
}
|
||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||
|
||||
viewModel.trySendAction(
|
||||
MainAction.ReceiveNewIntent(
|
||||
intent = mockIntent,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
SpecialCircumstance.VaultShortcut,
|
||||
specialCircumstanceManager.specialCircumstance,
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `on ReceiveNewIntent with a password generator deeplink data should set the special circumstance to GeneratorShortcut`() {
|
||||
val viewModel = createViewModel()
|
||||
val mockIntent = mockk<Intent> {
|
||||
every { getPasswordlessRequestDataIntentOrNull() } returns null
|
||||
every { getAutofillSaveItemOrNull() } returns null
|
||||
every { getAutofillSelectionDataOrNull() } returns null
|
||||
every { isMyVaultShortcut } returns false
|
||||
every { isPasswordGeneratorShortcut } returns true
|
||||
}
|
||||
every { intentManager.getShareDataFromIntent(mockIntent) } returns null
|
||||
|
||||
viewModel.trySendAction(
|
||||
MainAction.ReceiveNewIntent(
|
||||
intent = mockIntent,
|
||||
),
|
||||
)
|
||||
assertEquals(
|
||||
SpecialCircumstance.GeneratorShortcut,
|
||||
specialCircumstanceManager.specialCircumstance,
|
||||
)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `changes in the allowed screen capture value should result in emissions of ScreenCaptureSettingChange `() =
|
||||
|
|
|
@ -34,6 +34,12 @@ class SpecialCircumstanceExtensionsTest {
|
|||
data = mockk(),
|
||||
shouldFinishWhenComplete = true,
|
||||
),
|
||||
SpecialCircumstance.PasswordlessRequest(
|
||||
passwordlessRequestData = mockk(),
|
||||
shouldFinishWhenComplete = true,
|
||||
),
|
||||
SpecialCircumstance.GeneratorShortcut,
|
||||
SpecialCircumstance.VaultShortcut,
|
||||
)
|
||||
.forEach { specialCircumstance ->
|
||||
assertNull(specialCircumstance.toAutofillSaveItemOrNull())
|
||||
|
@ -67,6 +73,12 @@ class SpecialCircumstanceExtensionsTest {
|
|||
data = mockk(),
|
||||
shouldFinishWhenComplete = true,
|
||||
),
|
||||
SpecialCircumstance.PasswordlessRequest(
|
||||
passwordlessRequestData = mockk(),
|
||||
shouldFinishWhenComplete = true,
|
||||
),
|
||||
SpecialCircumstance.GeneratorShortcut,
|
||||
SpecialCircumstance.VaultShortcut,
|
||||
)
|
||||
.forEach { specialCircumstance ->
|
||||
assertNull(specialCircumstance.toAutofillSelectionDataOrNull())
|
||||
|
|
|
@ -2,6 +2,8 @@ package com.x8bit.bitwarden.ui.platform.feature.vaultunlockednavbar
|
|||
|
||||
import app.cash.turbine.test
|
||||
import com.x8bit.bitwarden.data.auth.repository.AuthRepository
|
||||
import com.x8bit.bitwarden.data.platform.manager.SpecialCircumstanceManager
|
||||
import com.x8bit.bitwarden.data.platform.manager.model.SpecialCircumstance
|
||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||
import io.mockk.every
|
||||
import io.mockk.just
|
||||
|
@ -16,6 +18,65 @@ class VaultUnlockedNavBarViewModelTest : BaseViewModelTest() {
|
|||
private val authRepository: AuthRepository = mockk {
|
||||
every { updateLastActiveTime() } just runs
|
||||
}
|
||||
private val specialCircumstancesManager: SpecialCircumstanceManager = mockk {
|
||||
every { specialCircumstance = null } just runs
|
||||
every { specialCircumstance } returns null
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `on init with GeneratorShortcut special circumstance should navigate to the generator screen`() =
|
||||
runTest {
|
||||
every {
|
||||
specialCircumstancesManager.specialCircumstance
|
||||
} returns SpecialCircumstance.GeneratorShortcut
|
||||
|
||||
val viewModel = createViewModel()
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
assertEquals(VaultUnlockedNavBarEvent.NavigateToGeneratorScreen, awaitItem())
|
||||
}
|
||||
verify(exactly = 1) {
|
||||
specialCircumstancesManager.specialCircumstance
|
||||
specialCircumstancesManager.specialCircumstance = null
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `on init with VaultShortcut special circumstance should navigate to the generator screen`() =
|
||||
runTest {
|
||||
every {
|
||||
specialCircumstancesManager.specialCircumstance
|
||||
} returns SpecialCircumstance.VaultShortcut
|
||||
|
||||
val viewModel = createViewModel()
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
assertEquals(VaultUnlockedNavBarEvent.NavigateToVaultScreen, awaitItem())
|
||||
}
|
||||
verify(exactly = 1) {
|
||||
specialCircumstancesManager.specialCircumstance
|
||||
specialCircumstancesManager.specialCircumstance = null
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on init with no shortcut special circumstance should do nothing`() = runTest {
|
||||
every { specialCircumstancesManager.specialCircumstance } returns null
|
||||
|
||||
val viewModel = createViewModel()
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
expectNoEvents()
|
||||
}
|
||||
verify(exactly = 1) {
|
||||
specialCircumstancesManager.specialCircumstance
|
||||
}
|
||||
verify(exactly = 0) {
|
||||
specialCircumstancesManager.specialCircumstance = null
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `VaultTabClick should navigate to the vault screen`() = runTest {
|
||||
|
@ -63,5 +124,6 @@ class VaultUnlockedNavBarViewModelTest : BaseViewModelTest() {
|
|||
private fun createViewModel() =
|
||||
VaultUnlockedNavBarViewModel(
|
||||
authRepository = authRepository,
|
||||
specialCircumstancesManager = specialCircumstancesManager,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
package com.x8bit.bitwarden.ui.platform.util
|
||||
|
||||
import android.content.Intent
|
||||
import io.mockk.every
|
||||
import io.mockk.mockk
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class ShortcutUtilsTest {
|
||||
@Test
|
||||
fun `isMyVaultShortcut should return true when dataString is my vault deeplink`() {
|
||||
val mockIntent = mockk<Intent> {
|
||||
every { dataString } returns "bitwarden://my_vault"
|
||||
}
|
||||
assertTrue(mockIntent.isMyVaultShortcut)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `isMyVaultShortcut should return false when dataString is not my vault deeplink`() {
|
||||
val mockIntent = mockk<Intent> {
|
||||
every { dataString } returns "bitwarden://some_other_vault"
|
||||
}
|
||||
assertFalse(mockIntent.isMyVaultShortcut)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `isMyVaultShortcut should return false when dataString is null`() {
|
||||
val mockIntent = mockk<Intent> {
|
||||
every { dataString } returns null
|
||||
}
|
||||
assertFalse(mockIntent.isMyVaultShortcut)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `isPasswordGeneratorShortcut should return true when dataString is my vault deeplink`() {
|
||||
val mockIntent = mockk<Intent> {
|
||||
every { dataString } returns "bitwarden://password_generator"
|
||||
}
|
||||
assertTrue(mockIntent.isPasswordGeneratorShortcut)
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `isPasswordGeneratorShortcut should return false when dataString is not my vault deeplink`() {
|
||||
val mockIntent = mockk<Intent> {
|
||||
every { dataString } returns "bitwarden://some_other_generator"
|
||||
}
|
||||
assertFalse(mockIntent.isPasswordGeneratorShortcut)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `isPasswordGeneratorShortcut should return false when dataString is null`() {
|
||||
val mockIntent = mockk<Intent> {
|
||||
every { dataString } returns null
|
||||
}
|
||||
assertFalse(mockIntent.isPasswordGeneratorShortcut)
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue