mirror of
https://github.com/bitwarden/android.git
synced 2024-11-27 20:10:33 +03:00
Add basic navigation for the search screen (#707)
This commit is contained in:
parent
e3547f4e13
commit
75fbadb67b
27 changed files with 728 additions and 21 deletions
|
@ -0,0 +1,131 @@
|
||||||
|
package com.x8bit.bitwarden.ui.platform.feature.search
|
||||||
|
|
||||||
|
import androidx.lifecycle.SavedStateHandle
|
||||||
|
import androidx.navigation.NavController
|
||||||
|
import androidx.navigation.NavGraphBuilder
|
||||||
|
import androidx.navigation.NavOptions
|
||||||
|
import androidx.navigation.NavType
|
||||||
|
import androidx.navigation.navArgument
|
||||||
|
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.util.composableWithSlideTransitions
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||||
|
|
||||||
|
private const val SEARCH_TYPE: String = "search_type"
|
||||||
|
private const val SEARCH_TYPE_SEND_ALL: String = "search_type_sends_all"
|
||||||
|
private const val SEARCH_TYPE_SEND_TEXT: String = "search_type_sends_text"
|
||||||
|
private const val SEARCH_TYPE_SEND_FILE: String = "search_type_sends_file"
|
||||||
|
private const val SEARCH_TYPE_VAULT_ALL: String = "search_type_vault_all"
|
||||||
|
private const val SEARCH_TYPE_VAULT_LOGINS: String = "search_type_vault_logins"
|
||||||
|
private const val SEARCH_TYPE_VAULT_CARDS: String = "search_type_vault_cards"
|
||||||
|
private const val SEARCH_TYPE_VAULT_IDENTITIES: String = "search_type_vault_identities"
|
||||||
|
private const val SEARCH_TYPE_VAULT_SECURE_NOTES: String = "search_type_vault_secure_notes"
|
||||||
|
private const val SEARCH_TYPE_VAULT_COLLECTION: String = "search_type_vault_collection"
|
||||||
|
private const val SEARCH_TYPE_VAULT_NO_FOLDER: String = "search_type_vault_no_folder"
|
||||||
|
private const val SEARCH_TYPE_VAULT_FOLDER: String = "search_type_vault_folder"
|
||||||
|
private const val SEARCH_TYPE_VAULT_TRASH: String = "search_type_vault_trash"
|
||||||
|
private const val SEARCH_TYPE_ID: String = "search_type_id"
|
||||||
|
|
||||||
|
private const val SEARCH_ROUTE_PREFIX: String = "search"
|
||||||
|
private const val SEARCH_ROUTE: String = "$SEARCH_ROUTE_PREFIX/{$SEARCH_TYPE}/{$SEARCH_TYPE_ID}"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class to retrieve search arguments from the [SavedStateHandle].
|
||||||
|
*/
|
||||||
|
@OmitFromCoverage
|
||||||
|
data class SearchArgs(
|
||||||
|
val type: SearchType,
|
||||||
|
) {
|
||||||
|
constructor(savedStateHandle: SavedStateHandle) : this(
|
||||||
|
type = determineSearchType(
|
||||||
|
searchTypeString = requireNotNull(savedStateHandle.get<String>(SEARCH_TYPE)),
|
||||||
|
id = savedStateHandle.get<String>(SEARCH_TYPE_ID),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add search destinations to the nav graph.
|
||||||
|
*/
|
||||||
|
fun NavGraphBuilder.searchDestination(
|
||||||
|
onNavigateBack: () -> Unit,
|
||||||
|
) {
|
||||||
|
composableWithSlideTransitions(
|
||||||
|
route = SEARCH_ROUTE,
|
||||||
|
arguments = listOf(
|
||||||
|
navArgument(SEARCH_TYPE) { type = NavType.StringType },
|
||||||
|
navArgument(SEARCH_TYPE_ID) {
|
||||||
|
type = NavType.StringType
|
||||||
|
nullable = true
|
||||||
|
},
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
SearchScreen(
|
||||||
|
onNavigateBack = onNavigateBack,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to the search screen.
|
||||||
|
*/
|
||||||
|
fun NavController.navigateToSearch(
|
||||||
|
searchType: SearchType,
|
||||||
|
navOptions: NavOptions? = null,
|
||||||
|
) {
|
||||||
|
navigate(
|
||||||
|
route = "$SEARCH_ROUTE_PREFIX/${searchType.toTypeString()}/${searchType.toIdOrNull()}",
|
||||||
|
navOptions = navOptions,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun determineSearchType(
|
||||||
|
searchTypeString: String,
|
||||||
|
id: String?,
|
||||||
|
): SearchType =
|
||||||
|
when (searchTypeString) {
|
||||||
|
SEARCH_TYPE_SEND_ALL -> SearchType.Sends.All
|
||||||
|
SEARCH_TYPE_SEND_TEXT -> SearchType.Sends.Texts
|
||||||
|
SEARCH_TYPE_SEND_FILE -> SearchType.Sends.Files
|
||||||
|
SEARCH_TYPE_VAULT_ALL -> SearchType.Vault.All
|
||||||
|
SEARCH_TYPE_VAULT_LOGINS -> SearchType.Vault.Logins
|
||||||
|
SEARCH_TYPE_VAULT_CARDS -> SearchType.Vault.Cards
|
||||||
|
SEARCH_TYPE_VAULT_IDENTITIES -> SearchType.Vault.Identities
|
||||||
|
SEARCH_TYPE_VAULT_SECURE_NOTES -> SearchType.Vault.SecureNotes
|
||||||
|
SEARCH_TYPE_VAULT_COLLECTION -> SearchType.Vault.Collection(requireNotNull(id))
|
||||||
|
SEARCH_TYPE_VAULT_NO_FOLDER -> SearchType.Vault.NoFolder
|
||||||
|
SEARCH_TYPE_VAULT_FOLDER -> SearchType.Vault.Folder(requireNotNull(id))
|
||||||
|
SEARCH_TYPE_VAULT_TRASH -> SearchType.Vault.Trash
|
||||||
|
else -> throw IllegalArgumentException("Invalid Search Type")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SearchType.toTypeString(): String =
|
||||||
|
when (this) {
|
||||||
|
SearchType.Sends.All -> SEARCH_TYPE_SEND_ALL
|
||||||
|
SearchType.Sends.Files -> SEARCH_TYPE_SEND_FILE
|
||||||
|
SearchType.Sends.Texts -> SEARCH_TYPE_SEND_TEXT
|
||||||
|
SearchType.Vault.All -> SEARCH_TYPE_VAULT_ALL
|
||||||
|
SearchType.Vault.Cards -> SEARCH_TYPE_VAULT_CARDS
|
||||||
|
is SearchType.Vault.Collection -> SEARCH_TYPE_VAULT_COLLECTION
|
||||||
|
is SearchType.Vault.Folder -> SEARCH_TYPE_VAULT_FOLDER
|
||||||
|
SearchType.Vault.Identities -> SEARCH_TYPE_VAULT_IDENTITIES
|
||||||
|
SearchType.Vault.Logins -> SEARCH_TYPE_VAULT_LOGINS
|
||||||
|
SearchType.Vault.NoFolder -> SEARCH_TYPE_VAULT_NO_FOLDER
|
||||||
|
SearchType.Vault.SecureNotes -> SEARCH_TYPE_VAULT_SECURE_NOTES
|
||||||
|
SearchType.Vault.Trash -> SEARCH_TYPE_VAULT_TRASH
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun SearchType.toIdOrNull(): String? =
|
||||||
|
when (this) {
|
||||||
|
SearchType.Sends.All -> null
|
||||||
|
SearchType.Sends.Files -> null
|
||||||
|
SearchType.Sends.Texts -> null
|
||||||
|
SearchType.Vault.All -> null
|
||||||
|
SearchType.Vault.Cards -> null
|
||||||
|
is SearchType.Vault.Collection -> collectionId
|
||||||
|
is SearchType.Vault.Folder -> folderId
|
||||||
|
SearchType.Vault.Identities -> null
|
||||||
|
SearchType.Vault.Logins -> null
|
||||||
|
SearchType.Vault.NoFolder -> null
|
||||||
|
SearchType.Vault.SecureNotes -> null
|
||||||
|
SearchType.Vault.Trash -> null
|
||||||
|
}
|
|
@ -0,0 +1,84 @@
|
||||||
|
package com.x8bit.bitwarden.ui.platform.feature.search
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.rememberScrollState
|
||||||
|
import androidx.compose.foundation.verticalScroll
|
||||||
|
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||||
|
import androidx.compose.material3.Text
|
||||||
|
import androidx.compose.material3.TopAppBarDefaults
|
||||||
|
import androidx.compose.material3.rememberTopAppBarState
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
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.res.painterResource
|
||||||
|
import androidx.compose.ui.res.stringResource
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
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.components.BitwardenScaffold
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.BitwardenTopAppBar
|
||||||
|
import com.x8bit.bitwarden.ui.platform.components.NavigationIcon
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The search UI for vault items or send items.
|
||||||
|
*/
|
||||||
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
@Composable
|
||||||
|
fun SearchScreen(
|
||||||
|
onNavigateBack: () -> Unit,
|
||||||
|
viewModel: SearchViewModel = hiltViewModel(),
|
||||||
|
) {
|
||||||
|
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||||
|
EventsEffect(viewModel = viewModel) { event ->
|
||||||
|
when (event) {
|
||||||
|
SearchEvent.NavigateBack -> onNavigateBack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val scrollBehavior = TopAppBarDefaults.pinnedScrollBehavior(rememberTopAppBarState())
|
||||||
|
BitwardenScaffold(
|
||||||
|
modifier = Modifier
|
||||||
|
.fillMaxSize()
|
||||||
|
.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||||
|
topBar = {
|
||||||
|
// TODO: Implement search appbar (BIT-640)
|
||||||
|
BitwardenTopAppBar(
|
||||||
|
title = "Search",
|
||||||
|
scrollBehavior = scrollBehavior,
|
||||||
|
navigationIcon = NavigationIcon(
|
||||||
|
navigationIcon = painterResource(id = R.drawable.ic_close),
|
||||||
|
navigationIconContentDescription = stringResource(id = R.string.close),
|
||||||
|
onNavigationIconClick = remember(viewModel) {
|
||||||
|
{ viewModel.trySendAction(SearchAction.BackClick) }
|
||||||
|
},
|
||||||
|
),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
) { innerPadding ->
|
||||||
|
Column(
|
||||||
|
modifier = Modifier
|
||||||
|
.padding(innerPadding)
|
||||||
|
.fillMaxSize()
|
||||||
|
.verticalScroll(rememberScrollState()),
|
||||||
|
verticalArrangement = Arrangement.Center,
|
||||||
|
horizontalAlignment = Alignment.CenterHorizontally,
|
||||||
|
) {
|
||||||
|
// TODO: Search Bar (BIT-640)
|
||||||
|
Text(text = state.searchType.toString())
|
||||||
|
Spacer(modifier = Modifier.height(8.dp))
|
||||||
|
Text(text = "Not yet implemented")
|
||||||
|
Spacer(modifier = Modifier.navigationBarsPadding())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
package com.x8bit.bitwarden.ui.platform.feature.search
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import androidx.lifecycle.SavedStateHandle
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||||
|
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private const val KEY_STATE = "state"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* View model for the search screen.
|
||||||
|
*/
|
||||||
|
@HiltViewModel
|
||||||
|
class SearchViewModel @Inject constructor(
|
||||||
|
savedStateHandle: SavedStateHandle,
|
||||||
|
) : BaseViewModel<SearchState, SearchEvent, SearchAction>(
|
||||||
|
// We load the state from the savedStateHandle for testing purposes.
|
||||||
|
initialState = savedStateHandle[KEY_STATE]
|
||||||
|
?: SearchState(
|
||||||
|
searchType = SearchArgs(savedStateHandle).type,
|
||||||
|
),
|
||||||
|
) {
|
||||||
|
override fun handleAction(action: SearchAction) {
|
||||||
|
when (action) {
|
||||||
|
SearchAction.BackClick -> handleBackClick()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleBackClick() {
|
||||||
|
sendEvent(SearchEvent.NavigateBack)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the overall state for the [SearchScreen].
|
||||||
|
*/
|
||||||
|
@Parcelize
|
||||||
|
data class SearchState(
|
||||||
|
val searchType: SearchType,
|
||||||
|
) : Parcelable
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Models actions for the [SearchScreen].
|
||||||
|
*/
|
||||||
|
sealed class SearchAction {
|
||||||
|
/**
|
||||||
|
* User clicked the back button.
|
||||||
|
*/
|
||||||
|
data object BackClick : SearchAction()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Models events for the [SearchScreen].
|
||||||
|
*/
|
||||||
|
sealed class SearchEvent {
|
||||||
|
/**
|
||||||
|
* Navigates back to the previous screen.
|
||||||
|
*/
|
||||||
|
data object NavigateBack : SearchEvent()
|
||||||
|
}
|
|
@ -0,0 +1,85 @@
|
||||||
|
package com.x8bit.bitwarden.ui.platform.feature.search.model
|
||||||
|
|
||||||
|
import android.os.Parcelable
|
||||||
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents the difference between searching sends and searching vault items.
|
||||||
|
*/
|
||||||
|
sealed class SearchType : Parcelable {
|
||||||
|
/**
|
||||||
|
* Indicates that we should be searching sends.
|
||||||
|
*/
|
||||||
|
@Parcelize
|
||||||
|
sealed class Sends : SearchType() {
|
||||||
|
/**
|
||||||
|
* Indicates that we should be searching all sends.
|
||||||
|
*/
|
||||||
|
data object All : Sends()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that we should be searching only text sends.
|
||||||
|
*/
|
||||||
|
data object Texts : Sends()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that we should be searching only file sends.
|
||||||
|
*/
|
||||||
|
data object Files : Sends()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that we should be searching vault items.
|
||||||
|
*/
|
||||||
|
@Parcelize
|
||||||
|
sealed class Vault : SearchType() {
|
||||||
|
/**
|
||||||
|
* Indicates that we should be searching all vault items.
|
||||||
|
*/
|
||||||
|
data object All : Vault()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that we should be searching only login ciphers.
|
||||||
|
*/
|
||||||
|
data object Logins : Vault()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that we should be searching only card ciphers.
|
||||||
|
*/
|
||||||
|
data object Cards : Vault()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that we should be searching only identity ciphers.
|
||||||
|
*/
|
||||||
|
data object Identities : Vault()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that we should be searching only secure note ciphers.
|
||||||
|
*/
|
||||||
|
data object SecureNotes : Vault()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that we should be searching only ciphers in the given collection.
|
||||||
|
*/
|
||||||
|
data class Collection(
|
||||||
|
val collectionId: String,
|
||||||
|
) : Vault()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that we should be searching only ciphers not in a folder.
|
||||||
|
*/
|
||||||
|
data object NoFolder : Vault()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that we should be searching only ciphers in the given folder.
|
||||||
|
*/
|
||||||
|
data class Folder(
|
||||||
|
val folderId: String,
|
||||||
|
) : Vault()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Indicates that we should be searching only ciphers in the trash.
|
||||||
|
*/
|
||||||
|
data object Trash : Vault()
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,6 +4,8 @@ import androidx.navigation.NavController
|
||||||
import androidx.navigation.NavGraphBuilder
|
import androidx.navigation.NavGraphBuilder
|
||||||
import androidx.navigation.NavOptions
|
import androidx.navigation.NavOptions
|
||||||
import androidx.navigation.navigation
|
import androidx.navigation.navigation
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.navigateToSearch
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.searchDestination
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity.deleteaccount.deleteAccountDestination
|
import com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity.deleteaccount.deleteAccountDestination
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity.deleteaccount.navigateToDeleteAccount
|
import com.x8bit.bitwarden.ui.platform.feature.settings.accountsecurity.deleteaccount.navigateToDeleteAccount
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.settings.folders.foldersDestination
|
import com.x8bit.bitwarden.ui.platform.feature.settings.folders.foldersDestination
|
||||||
|
@ -67,6 +69,8 @@ fun NavGraphBuilder.vaultUnlockedGraph(
|
||||||
onNavigateToVaultEditItem = {
|
onNavigateToVaultEditItem = {
|
||||||
navController.navigateToVaultAddEdit(VaultAddEditType.EditItem(it))
|
navController.navigateToVaultAddEdit(VaultAddEditType.EditItem(it))
|
||||||
},
|
},
|
||||||
|
onNavigateToSearchVault = { navController.navigateToSearch(searchType = it) },
|
||||||
|
onNavigateToSearchSend = { navController.navigateToSearch(searchType = it) },
|
||||||
onNavigateToAddSend = { navController.navigateToAddSend(AddSendType.AddItem) },
|
onNavigateToAddSend = { navController.navigateToAddSend(AddSendType.AddItem) },
|
||||||
onNavigateToEditSend = { navController.navigateToAddSend(AddSendType.EditItem(it)) },
|
onNavigateToEditSend = { navController.navigateToAddSend(AddSendType.EditItem(it)) },
|
||||||
onNavigateToDeleteAccount = { navController.navigateToDeleteAccount() },
|
onNavigateToDeleteAccount = { navController.navigateToDeleteAccount() },
|
||||||
|
@ -114,6 +118,7 @@ fun NavGraphBuilder.vaultUnlockedGraph(
|
||||||
passwordHistoryDestination(onNavigateBack = { navController.popBackStack() })
|
passwordHistoryDestination(onNavigateBack = { navController.popBackStack() })
|
||||||
foldersDestination(onNavigateBack = { navController.popBackStack() })
|
foldersDestination(onNavigateBack = { navController.popBackStack() })
|
||||||
generatorModalDestination(onNavigateBack = { navController.popBackStack() })
|
generatorModalDestination(onNavigateBack = { navController.popBackStack() })
|
||||||
|
searchDestination(onNavigateBack = { navController.popBackStack() })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ import androidx.navigation.NavController
|
||||||
import androidx.navigation.NavGraphBuilder
|
import androidx.navigation.NavGraphBuilder
|
||||||
import androidx.navigation.NavOptions
|
import androidx.navigation.NavOptions
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.composableWithStayTransitions
|
import com.x8bit.bitwarden.ui.platform.base.util.composableWithStayTransitions
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The functions below pertain to entry into the [VaultUnlockedNavBarScreen].
|
* The functions below pertain to entry into the [VaultUnlockedNavBarScreen].
|
||||||
|
@ -25,6 +26,8 @@ fun NavGraphBuilder.vaultUnlockedNavBarDestination(
|
||||||
onNavigateToVaultAddItem: () -> Unit,
|
onNavigateToVaultAddItem: () -> Unit,
|
||||||
onNavigateToVaultItem: (vaultItemId: String) -> Unit,
|
onNavigateToVaultItem: (vaultItemId: String) -> Unit,
|
||||||
onNavigateToVaultEditItem: (vaultItemId: String) -> Unit,
|
onNavigateToVaultEditItem: (vaultItemId: String) -> Unit,
|
||||||
|
onNavigateToSearchSend: (searchType: SearchType.Sends) -> Unit,
|
||||||
|
onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit,
|
||||||
onNavigateToAddSend: () -> Unit,
|
onNavigateToAddSend: () -> Unit,
|
||||||
onNavigateToEditSend: (sendItemId: String) -> Unit,
|
onNavigateToEditSend: (sendItemId: String) -> Unit,
|
||||||
onNavigateToDeleteAccount: () -> Unit,
|
onNavigateToDeleteAccount: () -> Unit,
|
||||||
|
@ -38,6 +41,8 @@ fun NavGraphBuilder.vaultUnlockedNavBarDestination(
|
||||||
onNavigateToVaultAddItem = onNavigateToVaultAddItem,
|
onNavigateToVaultAddItem = onNavigateToVaultAddItem,
|
||||||
onNavigateToVaultItem = onNavigateToVaultItem,
|
onNavigateToVaultItem = onNavigateToVaultItem,
|
||||||
onNavigateToVaultEditItem = onNavigateToVaultEditItem,
|
onNavigateToVaultEditItem = onNavigateToVaultEditItem,
|
||||||
|
onNavigateToSearchSend = onNavigateToSearchSend,
|
||||||
|
onNavigateToSearchVault = onNavigateToSearchVault,
|
||||||
onNavigateToAddSend = onNavigateToAddSend,
|
onNavigateToAddSend = onNavigateToAddSend,
|
||||||
onNavigateToEditSend = onNavigateToEditSend,
|
onNavigateToEditSend = onNavigateToEditSend,
|
||||||
onNavigateToDeleteAccount = onNavigateToDeleteAccount,
|
onNavigateToDeleteAccount = onNavigateToDeleteAccount,
|
||||||
|
|
|
@ -46,6 +46,7 @@ import com.x8bit.bitwarden.ui.platform.base.util.max
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.toDp
|
import com.x8bit.bitwarden.ui.platform.base.util.toDp
|
||||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenAnimatedScrim
|
import com.x8bit.bitwarden.ui.platform.components.BitwardenAnimatedScrim
|
||||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenScaffold
|
import com.x8bit.bitwarden.ui.platform.components.BitwardenScaffold
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.settings.SETTINGS_GRAPH_ROUTE
|
import com.x8bit.bitwarden.ui.platform.feature.settings.SETTINGS_GRAPH_ROUTE
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.settings.navigateToSettingsGraph
|
import com.x8bit.bitwarden.ui.platform.feature.settings.navigateToSettingsGraph
|
||||||
import com.x8bit.bitwarden.ui.platform.feature.settings.settingsGraph
|
import com.x8bit.bitwarden.ui.platform.feature.settings.settingsGraph
|
||||||
|
@ -74,6 +75,8 @@ fun VaultUnlockedNavBarScreen(
|
||||||
onNavigateToVaultAddItem: () -> Unit,
|
onNavigateToVaultAddItem: () -> Unit,
|
||||||
onNavigateToVaultItem: (vaultItemId: String) -> Unit,
|
onNavigateToVaultItem: (vaultItemId: String) -> Unit,
|
||||||
onNavigateToVaultEditItem: (vaultItemId: String) -> Unit,
|
onNavigateToVaultEditItem: (vaultItemId: String) -> Unit,
|
||||||
|
onNavigateToSearchSend: (searchType: SearchType.Sends) -> Unit,
|
||||||
|
onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit,
|
||||||
onNavigateToAddSend: () -> Unit,
|
onNavigateToAddSend: () -> Unit,
|
||||||
onNavigateToEditSend: (sendItemId: String) -> Unit,
|
onNavigateToEditSend: (sendItemId: String) -> Unit,
|
||||||
onNavigateToDeleteAccount: () -> Unit,
|
onNavigateToDeleteAccount: () -> Unit,
|
||||||
|
@ -116,6 +119,8 @@ fun VaultUnlockedNavBarScreen(
|
||||||
onNavigateToVaultItem = onNavigateToVaultItem,
|
onNavigateToVaultItem = onNavigateToVaultItem,
|
||||||
onNavigateToVaultEditItem = onNavigateToVaultEditItem,
|
onNavigateToVaultEditItem = onNavigateToVaultEditItem,
|
||||||
navigateToVaultAddItem = onNavigateToVaultAddItem,
|
navigateToVaultAddItem = onNavigateToVaultAddItem,
|
||||||
|
onNavigateToSearchSend = onNavigateToSearchSend,
|
||||||
|
onNavigateToSearchVault = onNavigateToSearchVault,
|
||||||
navigateToAddSend = onNavigateToAddSend,
|
navigateToAddSend = onNavigateToAddSend,
|
||||||
onNavigateToEditSend = onNavigateToEditSend,
|
onNavigateToEditSend = onNavigateToEditSend,
|
||||||
navigateToDeleteAccount = onNavigateToDeleteAccount,
|
navigateToDeleteAccount = onNavigateToDeleteAccount,
|
||||||
|
@ -151,6 +156,8 @@ private fun VaultUnlockedNavBarScaffold(
|
||||||
navigateToVaultAddItem: () -> Unit,
|
navigateToVaultAddItem: () -> Unit,
|
||||||
onNavigateToVaultItem: (vaultItemId: String) -> Unit,
|
onNavigateToVaultItem: (vaultItemId: String) -> Unit,
|
||||||
onNavigateToVaultEditItem: (vaultItemId: String) -> Unit,
|
onNavigateToVaultEditItem: (vaultItemId: String) -> Unit,
|
||||||
|
onNavigateToSearchSend: (searchType: SearchType.Sends) -> Unit,
|
||||||
|
onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit,
|
||||||
navigateToAddSend: () -> Unit,
|
navigateToAddSend: () -> Unit,
|
||||||
onNavigateToEditSend: (sendItemId: String) -> Unit,
|
onNavigateToEditSend: (sendItemId: String) -> Unit,
|
||||||
navigateToDeleteAccount: () -> Unit,
|
navigateToDeleteAccount: () -> Unit,
|
||||||
|
@ -210,6 +217,7 @@ private fun VaultUnlockedNavBarScaffold(
|
||||||
onNavigateToVaultAddItemScreen = navigateToVaultAddItem,
|
onNavigateToVaultAddItemScreen = navigateToVaultAddItem,
|
||||||
onNavigateToVaultItemScreen = onNavigateToVaultItem,
|
onNavigateToVaultItemScreen = onNavigateToVaultItem,
|
||||||
onNavigateToVaultEditItemScreen = onNavigateToVaultEditItem,
|
onNavigateToVaultEditItemScreen = onNavigateToVaultEditItem,
|
||||||
|
onNavigateToSearchVault = onNavigateToSearchVault,
|
||||||
onDimBottomNavBarRequest = { shouldDim ->
|
onDimBottomNavBarRequest = { shouldDim ->
|
||||||
shouldDimNavBar = shouldDim
|
shouldDimNavBar = shouldDim
|
||||||
},
|
},
|
||||||
|
@ -218,6 +226,7 @@ private fun VaultUnlockedNavBarScaffold(
|
||||||
navController = navController,
|
navController = navController,
|
||||||
onNavigateToAddSend = navigateToAddSend,
|
onNavigateToAddSend = navigateToAddSend,
|
||||||
onNavigateToEditSend = onNavigateToEditSend,
|
onNavigateToEditSend = onNavigateToEditSend,
|
||||||
|
onNavigateToSearchSend = onNavigateToSearchSend,
|
||||||
)
|
)
|
||||||
generatorGraph(
|
generatorGraph(
|
||||||
onNavigateToPasswordHistory = { navigateToPasswordHistory() },
|
onNavigateToPasswordHistory = { navigateToPasswordHistory() },
|
||||||
|
|
|
@ -4,6 +4,7 @@ import androidx.navigation.NavController
|
||||||
import androidx.navigation.NavGraphBuilder
|
import androidx.navigation.NavGraphBuilder
|
||||||
import androidx.navigation.NavOptions
|
import androidx.navigation.NavOptions
|
||||||
import androidx.navigation.navigation
|
import androidx.navigation.navigation
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.navigateToSendItemListing
|
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.navigateToSendItemListing
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.sendItemListingDestination
|
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.sendItemListingDestination
|
||||||
import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType
|
import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType
|
||||||
|
@ -17,6 +18,7 @@ fun NavGraphBuilder.sendGraph(
|
||||||
navController: NavController,
|
navController: NavController,
|
||||||
onNavigateToAddSend: () -> Unit,
|
onNavigateToAddSend: () -> Unit,
|
||||||
onNavigateToEditSend: (sendItemId: String) -> Unit,
|
onNavigateToEditSend: (sendItemId: String) -> Unit,
|
||||||
|
onNavigateToSearchSend: (searchType: SearchType.Sends) -> Unit,
|
||||||
) {
|
) {
|
||||||
navigation(
|
navigation(
|
||||||
startDestination = SEND_ROUTE,
|
startDestination = SEND_ROUTE,
|
||||||
|
@ -31,11 +33,13 @@ fun NavGraphBuilder.sendGraph(
|
||||||
onNavigateToSendTextList = {
|
onNavigateToSendTextList = {
|
||||||
navController.navigateToSendItemListing(VaultItemListingType.SendText)
|
navController.navigateToSendItemListing(VaultItemListingType.SendText)
|
||||||
},
|
},
|
||||||
|
onNavigateToSearchSend = onNavigateToSearchSend,
|
||||||
)
|
)
|
||||||
sendItemListingDestination(
|
sendItemListingDestination(
|
||||||
onNavigateBack = { navController.popBackStack() },
|
onNavigateBack = { navController.popBackStack() },
|
||||||
onNavigateToAddSendItem = onNavigateToAddSend,
|
onNavigateToAddSendItem = onNavigateToAddSend,
|
||||||
onNavigateToEditSendItem = onNavigateToEditSend,
|
onNavigateToEditSendItem = onNavigateToEditSend,
|
||||||
|
onNavigateToSearchSend = onNavigateToSearchSend,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import androidx.navigation.NavController
|
||||||
import androidx.navigation.NavGraphBuilder
|
import androidx.navigation.NavGraphBuilder
|
||||||
import androidx.navigation.NavOptions
|
import androidx.navigation.NavOptions
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.composableWithRootPushTransitions
|
import com.x8bit.bitwarden.ui.platform.base.util.composableWithRootPushTransitions
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||||
|
|
||||||
const val SEND_ROUTE: String = "send"
|
const val SEND_ROUTE: String = "send"
|
||||||
|
|
||||||
|
@ -15,6 +16,7 @@ fun NavGraphBuilder.sendDestination(
|
||||||
onNavigateToEditSend: (sendItemId: String) -> Unit,
|
onNavigateToEditSend: (sendItemId: String) -> Unit,
|
||||||
onNavigateToSendFilesList: () -> Unit,
|
onNavigateToSendFilesList: () -> Unit,
|
||||||
onNavigateToSendTextList: () -> Unit,
|
onNavigateToSendTextList: () -> Unit,
|
||||||
|
onNavigateToSearchSend: (searchType: SearchType.Sends) -> Unit,
|
||||||
) {
|
) {
|
||||||
composableWithRootPushTransitions(
|
composableWithRootPushTransitions(
|
||||||
route = SEND_ROUTE,
|
route = SEND_ROUTE,
|
||||||
|
@ -24,6 +26,7 @@ fun NavGraphBuilder.sendDestination(
|
||||||
onNavigateToEditSend = onNavigateToEditSend,
|
onNavigateToEditSend = onNavigateToEditSend,
|
||||||
onNavigateToSendFilesList = onNavigateToSendFilesList,
|
onNavigateToSendFilesList = onNavigateToSendFilesList,
|
||||||
onNavigateToSendTextList = onNavigateToSendTextList,
|
onNavigateToSendTextList = onNavigateToSendTextList,
|
||||||
|
onNavigateToSearchSend = onNavigateToSearchSend,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ import com.x8bit.bitwarden.ui.platform.components.BitwardenScaffold
|
||||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenSearchActionItem
|
import com.x8bit.bitwarden.ui.platform.components.BitwardenSearchActionItem
|
||||||
import com.x8bit.bitwarden.ui.platform.components.LoadingDialogState
|
import com.x8bit.bitwarden.ui.platform.components.LoadingDialogState
|
||||||
import com.x8bit.bitwarden.ui.platform.components.OverflowMenuItemData
|
import com.x8bit.bitwarden.ui.platform.components.OverflowMenuItemData
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||||
import com.x8bit.bitwarden.ui.platform.theme.LocalIntentManager
|
import com.x8bit.bitwarden.ui.platform.theme.LocalIntentManager
|
||||||
import com.x8bit.bitwarden.ui.tools.feature.send.handlers.SendHandlers
|
import com.x8bit.bitwarden.ui.tools.feature.send.handlers.SendHandlers
|
||||||
|
@ -47,7 +48,7 @@ import kotlinx.collections.immutable.persistentListOf
|
||||||
/**
|
/**
|
||||||
* UI for the send screen.
|
* UI for the send screen.
|
||||||
*/
|
*/
|
||||||
@Suppress("LongMethod")
|
@Suppress("LongMethod", "CyclomaticComplexMethod")
|
||||||
@OptIn(ExperimentalMaterial3Api::class)
|
@OptIn(ExperimentalMaterial3Api::class)
|
||||||
@Composable
|
@Composable
|
||||||
fun SendScreen(
|
fun SendScreen(
|
||||||
|
@ -55,6 +56,7 @@ fun SendScreen(
|
||||||
onNavigateToEditSend: (sendItemId: String) -> Unit,
|
onNavigateToEditSend: (sendItemId: String) -> Unit,
|
||||||
onNavigateToSendFilesList: () -> Unit,
|
onNavigateToSendFilesList: () -> Unit,
|
||||||
onNavigateToSendTextList: () -> Unit,
|
onNavigateToSendTextList: () -> Unit,
|
||||||
|
onNavigateToSearchSend: (searchType: SearchType.Sends) -> Unit,
|
||||||
viewModel: SendViewModel = hiltViewModel(),
|
viewModel: SendViewModel = hiltViewModel(),
|
||||||
intentManager: IntentManager = LocalIntentManager.current,
|
intentManager: IntentManager = LocalIntentManager.current,
|
||||||
) {
|
) {
|
||||||
|
@ -72,6 +74,8 @@ fun SendScreen(
|
||||||
when (event) {
|
when (event) {
|
||||||
is SendEvent.DismissPullToRefresh -> pullToRefreshState?.endRefresh()
|
is SendEvent.DismissPullToRefresh -> pullToRefreshState?.endRefresh()
|
||||||
|
|
||||||
|
is SendEvent.NavigateToSearch -> onNavigateToSearchSend(SearchType.Sends.All)
|
||||||
|
|
||||||
is SendEvent.NavigateNewSend -> onNavigateToAddSend()
|
is SendEvent.NavigateNewSend -> onNavigateToAddSend()
|
||||||
|
|
||||||
is SendEvent.NavigateToEditSend -> onNavigateToEditSend(event.sendId)
|
is SendEvent.NavigateToEditSend -> onNavigateToEditSend(event.sendId)
|
||||||
|
|
|
@ -233,8 +233,7 @@ class SendViewModel @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSearchClick() {
|
private fun handleSearchClick() {
|
||||||
// TODO: navigate to send search BIT-594
|
sendEvent(SendEvent.NavigateToSearch)
|
||||||
sendEvent(SendEvent.ShowToast("Search Not Implemented".asText()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun handleSyncClick() {
|
private fun handleSyncClick() {
|
||||||
|
@ -566,6 +565,11 @@ sealed class SendEvent {
|
||||||
*/
|
*/
|
||||||
data object NavigateToFileSends : SendEvent()
|
data object NavigateToFileSends : SendEvent()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Navigate to the send search screen.
|
||||||
|
*/
|
||||||
|
data object NavigateToSearch : SendEvent()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Navigate to the send text screen.
|
* Navigate to the send text screen.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -8,6 +8,7 @@ import androidx.navigation.NavType
|
||||||
import androidx.navigation.navArgument
|
import androidx.navigation.navArgument
|
||||||
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.composableWithPushTransitions
|
import com.x8bit.bitwarden.ui.platform.base.util.composableWithPushTransitions
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||||
import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType
|
import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType
|
||||||
|
|
||||||
private const val CARD: String = "card"
|
private const val CARD: String = "card"
|
||||||
|
@ -54,6 +55,7 @@ fun NavGraphBuilder.vaultItemListingDestination(
|
||||||
onNavigateBack: () -> Unit,
|
onNavigateBack: () -> Unit,
|
||||||
onNavigateToVaultItemScreen: (id: String) -> Unit,
|
onNavigateToVaultItemScreen: (id: String) -> Unit,
|
||||||
onNavigateToVaultAddItemScreen: () -> Unit,
|
onNavigateToVaultAddItemScreen: () -> Unit,
|
||||||
|
onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit,
|
||||||
) {
|
) {
|
||||||
internalVaultItemListingDestination(
|
internalVaultItemListingDestination(
|
||||||
route = VAULT_ITEM_LISTING_ROUTE,
|
route = VAULT_ITEM_LISTING_ROUTE,
|
||||||
|
@ -62,6 +64,7 @@ fun NavGraphBuilder.vaultItemListingDestination(
|
||||||
onNavigateToEditSendItem = { },
|
onNavigateToEditSendItem = { },
|
||||||
onNavigateToVaultAddItemScreen = onNavigateToVaultAddItemScreen,
|
onNavigateToVaultAddItemScreen = onNavigateToVaultAddItemScreen,
|
||||||
onNavigateToVaultItemScreen = onNavigateToVaultItemScreen,
|
onNavigateToVaultItemScreen = onNavigateToVaultItemScreen,
|
||||||
|
onNavigateToSearch = { onNavigateToSearchVault(it as SearchType.Vault) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -72,6 +75,7 @@ fun NavGraphBuilder.sendItemListingDestination(
|
||||||
onNavigateBack: () -> Unit,
|
onNavigateBack: () -> Unit,
|
||||||
onNavigateToAddSendItem: () -> Unit,
|
onNavigateToAddSendItem: () -> Unit,
|
||||||
onNavigateToEditSendItem: (sendId: String) -> Unit,
|
onNavigateToEditSendItem: (sendId: String) -> Unit,
|
||||||
|
onNavigateToSearchSend: (searchType: SearchType.Sends) -> Unit,
|
||||||
) {
|
) {
|
||||||
internalVaultItemListingDestination(
|
internalVaultItemListingDestination(
|
||||||
route = SEND_ITEM_LISTING_ROUTE,
|
route = SEND_ITEM_LISTING_ROUTE,
|
||||||
|
@ -80,6 +84,7 @@ fun NavGraphBuilder.sendItemListingDestination(
|
||||||
onNavigateToEditSendItem = onNavigateToEditSendItem,
|
onNavigateToEditSendItem = onNavigateToEditSendItem,
|
||||||
onNavigateToVaultAddItemScreen = { },
|
onNavigateToVaultAddItemScreen = { },
|
||||||
onNavigateToVaultItemScreen = { },
|
onNavigateToVaultItemScreen = { },
|
||||||
|
onNavigateToSearch = { onNavigateToSearchSend(it as SearchType.Sends) },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,6 +99,7 @@ private fun NavGraphBuilder.internalVaultItemListingDestination(
|
||||||
onNavigateToVaultAddItemScreen: () -> Unit,
|
onNavigateToVaultAddItemScreen: () -> Unit,
|
||||||
onNavigateToAddSendItem: () -> Unit,
|
onNavigateToAddSendItem: () -> Unit,
|
||||||
onNavigateToEditSendItem: (sendId: String) -> Unit,
|
onNavigateToEditSendItem: (sendId: String) -> Unit,
|
||||||
|
onNavigateToSearch: (searchType: SearchType) -> Unit,
|
||||||
) {
|
) {
|
||||||
composableWithPushTransitions(
|
composableWithPushTransitions(
|
||||||
route = route,
|
route = route,
|
||||||
|
@ -117,6 +123,7 @@ private fun NavGraphBuilder.internalVaultItemListingDestination(
|
||||||
onNavigateToVaultAddItemScreen = onNavigateToVaultAddItemScreen,
|
onNavigateToVaultAddItemScreen = onNavigateToVaultAddItemScreen,
|
||||||
onNavigateToAddSendItem = onNavigateToAddSendItem,
|
onNavigateToAddSendItem = onNavigateToAddSendItem,
|
||||||
onNavigateToEditSendItem = onNavigateToEditSendItem,
|
onNavigateToEditSendItem = onNavigateToEditSendItem,
|
||||||
|
onNavigateToSearch = onNavigateToSearch,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ import com.x8bit.bitwarden.ui.platform.components.BitwardenSearchActionItem
|
||||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenTopAppBar
|
import com.x8bit.bitwarden.ui.platform.components.BitwardenTopAppBar
|
||||||
import com.x8bit.bitwarden.ui.platform.components.LoadingDialogState
|
import com.x8bit.bitwarden.ui.platform.components.LoadingDialogState
|
||||||
import com.x8bit.bitwarden.ui.platform.components.OverflowMenuItemData
|
import com.x8bit.bitwarden.ui.platform.components.OverflowMenuItemData
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||||
import com.x8bit.bitwarden.ui.platform.theme.LocalIntentManager
|
import com.x8bit.bitwarden.ui.platform.theme.LocalIntentManager
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.handlers.VaultItemListingHandlers
|
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.handlers.VaultItemListingHandlers
|
||||||
|
@ -51,6 +52,7 @@ fun VaultItemListingScreen(
|
||||||
onNavigateToVaultAddItemScreen: () -> Unit,
|
onNavigateToVaultAddItemScreen: () -> Unit,
|
||||||
onNavigateToAddSendItem: () -> Unit,
|
onNavigateToAddSendItem: () -> Unit,
|
||||||
onNavigateToEditSendItem: (sendId: String) -> Unit,
|
onNavigateToEditSendItem: (sendId: String) -> Unit,
|
||||||
|
onNavigateToSearch: (searchType: SearchType) -> Unit,
|
||||||
intentManager: IntentManager = LocalIntentManager.current,
|
intentManager: IntentManager = LocalIntentManager.current,
|
||||||
viewModel: VaultItemListingViewModel = hiltViewModel(),
|
viewModel: VaultItemListingViewModel = hiltViewModel(),
|
||||||
) {
|
) {
|
||||||
|
@ -94,11 +96,8 @@ fun VaultItemListingScreen(
|
||||||
onNavigateToEditSendItem(event.id)
|
onNavigateToEditSendItem(event.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
is VaultItemListingEvent.NavigateToVaultSearchScreen -> {
|
is VaultItemListingEvent.NavigateToSearchScreen -> {
|
||||||
// TODO Create vault search screen and navigation implementation BIT-213
|
onNavigateToSearch(event.searchType)
|
||||||
Toast
|
|
||||||
.makeText(context, "Navigate to the vault search screen.", Toast.LENGTH_SHORT)
|
|
||||||
.show()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,11 @@ import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.concat
|
import com.x8bit.bitwarden.ui.platform.base.util.concat
|
||||||
import com.x8bit.bitwarden.ui.platform.components.model.IconData
|
import com.x8bit.bitwarden.ui.platform.components.model.IconData
|
||||||
import com.x8bit.bitwarden.ui.platform.components.model.IconRes
|
import com.x8bit.bitwarden.ui.platform.components.model.IconRes
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.model.ListingItemOverflowAction
|
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.model.ListingItemOverflowAction
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.util.determineListingPredicate
|
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.util.determineListingPredicate
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.util.toItemListingType
|
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.util.toItemListingType
|
||||||
|
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.util.toSearchType
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.util.toViewState
|
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.util.toViewState
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.util.updateWithAdditionalDataIfNecessary
|
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.util.updateWithAdditionalDataIfNecessary
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterType
|
import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterType
|
||||||
|
@ -207,7 +209,9 @@ class VaultItemListingViewModel @Inject constructor(
|
||||||
|
|
||||||
private fun handleSearchIconClick() {
|
private fun handleSearchIconClick() {
|
||||||
sendEvent(
|
sendEvent(
|
||||||
event = VaultItemListingEvent.NavigateToVaultSearchScreen,
|
event = VaultItemListingEvent.NavigateToSearchScreen(
|
||||||
|
searchType = state.itemListingType.toSearchType(),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -693,9 +697,11 @@ sealed class VaultItemListingEvent {
|
||||||
data class NavigateToVaultItem(val id: String) : VaultItemListingEvent()
|
data class NavigateToVaultItem(val id: String) : VaultItemListingEvent()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Navigates to the VaultSearchScreen.
|
* Navigates to the SearchScreen with the given type filter.
|
||||||
*/
|
*/
|
||||||
data object NavigateToVaultSearchScreen : VaultItemListingEvent()
|
data class NavigateToSearchScreen(
|
||||||
|
val searchType: SearchType,
|
||||||
|
) : VaultItemListingEvent()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show a share sheet with the given content.
|
* Show a share sheet with the given content.
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package com.x8bit.bitwarden.ui.vault.feature.itemlisting.util
|
||||||
|
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||||
|
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.VaultItemListingState
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Transforms a [VaultItemListingState.ItemListingType] into a [SearchType].
|
||||||
|
*/
|
||||||
|
fun VaultItemListingState.ItemListingType.toSearchType(): SearchType =
|
||||||
|
when (this) {
|
||||||
|
is VaultItemListingState.ItemListingType.Vault.Card -> SearchType.Vault.Cards
|
||||||
|
is VaultItemListingState.ItemListingType.Vault.Folder -> {
|
||||||
|
folderId
|
||||||
|
?.let { SearchType.Vault.Folder(folderId = it) }
|
||||||
|
?: SearchType.Vault.NoFolder
|
||||||
|
}
|
||||||
|
|
||||||
|
is VaultItemListingState.ItemListingType.Vault.Identity -> SearchType.Vault.Identities
|
||||||
|
is VaultItemListingState.ItemListingType.Vault.Login -> SearchType.Vault.Logins
|
||||||
|
is VaultItemListingState.ItemListingType.Vault.SecureNote -> SearchType.Vault.SecureNotes
|
||||||
|
is VaultItemListingState.ItemListingType.Vault.Trash -> SearchType.Vault.Trash
|
||||||
|
is VaultItemListingState.ItemListingType.Vault.Collection -> {
|
||||||
|
SearchType.Vault.Collection(collectionId = collectionId)
|
||||||
|
}
|
||||||
|
|
||||||
|
is VaultItemListingState.ItemListingType.Send.SendFile -> SearchType.Sends.Files
|
||||||
|
is VaultItemListingState.ItemListingType.Send.SendText -> SearchType.Sends.Texts
|
||||||
|
}
|
|
@ -4,6 +4,7 @@ import androidx.navigation.NavController
|
||||||
import androidx.navigation.NavGraphBuilder
|
import androidx.navigation.NavGraphBuilder
|
||||||
import androidx.navigation.NavOptions
|
import androidx.navigation.NavOptions
|
||||||
import androidx.navigation.navigation
|
import androidx.navigation.navigation
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.navigateToVaultItemListing
|
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.navigateToVaultItemListing
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.vaultItemListingDestination
|
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.vaultItemListingDestination
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.verificationcode.navigateToVerificationCodeScreen
|
import com.x8bit.bitwarden.ui.vault.feature.verificationcode.navigateToVerificationCodeScreen
|
||||||
|
@ -14,11 +15,13 @@ const val VAULT_GRAPH_ROUTE: String = "vault_graph"
|
||||||
/**
|
/**
|
||||||
* Add vault destinations to the nav graph.
|
* Add vault destinations to the nav graph.
|
||||||
*/
|
*/
|
||||||
|
@Suppress("LongParameterList")
|
||||||
fun NavGraphBuilder.vaultGraph(
|
fun NavGraphBuilder.vaultGraph(
|
||||||
navController: NavController,
|
navController: NavController,
|
||||||
onNavigateToVaultAddItemScreen: () -> Unit,
|
onNavigateToVaultAddItemScreen: () -> Unit,
|
||||||
onNavigateToVaultItemScreen: (vaultItemId: String) -> Unit,
|
onNavigateToVaultItemScreen: (vaultItemId: String) -> Unit,
|
||||||
onNavigateToVaultEditItemScreen: (vaultItemId: String) -> Unit,
|
onNavigateToVaultEditItemScreen: (vaultItemId: String) -> Unit,
|
||||||
|
onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit,
|
||||||
onDimBottomNavBarRequest: (shouldDim: Boolean) -> Unit,
|
onDimBottomNavBarRequest: (shouldDim: Boolean) -> Unit,
|
||||||
) {
|
) {
|
||||||
navigation(
|
navigation(
|
||||||
|
@ -33,13 +36,14 @@ fun NavGraphBuilder.vaultGraph(
|
||||||
onNavigateToVerificationCodeScreen = {
|
onNavigateToVerificationCodeScreen = {
|
||||||
navController.navigateToVerificationCodeScreen()
|
navController.navigateToVerificationCodeScreen()
|
||||||
},
|
},
|
||||||
|
onNavigateToSearchVault = onNavigateToSearchVault,
|
||||||
onDimBottomNavBarRequest = onDimBottomNavBarRequest,
|
onDimBottomNavBarRequest = onDimBottomNavBarRequest,
|
||||||
)
|
)
|
||||||
vaultItemListingDestination(
|
vaultItemListingDestination(
|
||||||
onNavigateBack = { navController.popBackStack() },
|
onNavigateBack = { navController.popBackStack() },
|
||||||
onNavigateToVaultItemScreen = onNavigateToVaultItemScreen,
|
onNavigateToVaultItemScreen = onNavigateToVaultItemScreen,
|
||||||
onNavigateToVaultAddItemScreen = onNavigateToVaultAddItemScreen,
|
onNavigateToVaultAddItemScreen = onNavigateToVaultAddItemScreen,
|
||||||
|
onNavigateToSearchVault = onNavigateToSearchVault,
|
||||||
)
|
)
|
||||||
|
|
||||||
vaultVerificationCodeDestination(
|
vaultVerificationCodeDestination(
|
||||||
|
|
|
@ -4,6 +4,7 @@ import androidx.navigation.NavController
|
||||||
import androidx.navigation.NavGraphBuilder
|
import androidx.navigation.NavGraphBuilder
|
||||||
import androidx.navigation.NavOptions
|
import androidx.navigation.NavOptions
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.composableWithRootPushTransitions
|
import com.x8bit.bitwarden.ui.platform.base.util.composableWithRootPushTransitions
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||||
import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType
|
import com.x8bit.bitwarden.ui.vault.model.VaultItemListingType
|
||||||
|
|
||||||
const val VAULT_ROUTE: String = "vault"
|
const val VAULT_ROUTE: String = "vault"
|
||||||
|
@ -18,6 +19,7 @@ fun NavGraphBuilder.vaultDestination(
|
||||||
onNavigateToVaultItemScreen: (vaultItemId: String) -> Unit,
|
onNavigateToVaultItemScreen: (vaultItemId: String) -> Unit,
|
||||||
onNavigateToVaultEditItemScreen: (vaultItemId: String) -> Unit,
|
onNavigateToVaultEditItemScreen: (vaultItemId: String) -> Unit,
|
||||||
onNavigateToVaultItemListingScreen: (vaultItemType: VaultItemListingType) -> Unit,
|
onNavigateToVaultItemListingScreen: (vaultItemType: VaultItemListingType) -> Unit,
|
||||||
|
onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit,
|
||||||
onDimBottomNavBarRequest: (shouldDim: Boolean) -> Unit,
|
onDimBottomNavBarRequest: (shouldDim: Boolean) -> Unit,
|
||||||
) {
|
) {
|
||||||
composableWithRootPushTransitions(
|
composableWithRootPushTransitions(
|
||||||
|
@ -29,6 +31,7 @@ fun NavGraphBuilder.vaultDestination(
|
||||||
onNavigateToVaultEditItemScreen = onNavigateToVaultEditItemScreen,
|
onNavigateToVaultEditItemScreen = onNavigateToVaultEditItemScreen,
|
||||||
onNavigateToVaultItemListingScreen = onNavigateToVaultItemListingScreen,
|
onNavigateToVaultItemListingScreen = onNavigateToVaultItemListingScreen,
|
||||||
onNavigateToVerificationCodeScreen = onNavigateToVerificationCodeScreen,
|
onNavigateToVerificationCodeScreen = onNavigateToVerificationCodeScreen,
|
||||||
|
onNavigateToSearchVault = onNavigateToSearchVault,
|
||||||
onDimBottomNavBarRequest = onDimBottomNavBarRequest,
|
onDimBottomNavBarRequest = onDimBottomNavBarRequest,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,6 +51,7 @@ import com.x8bit.bitwarden.ui.platform.components.BitwardenTwoButtonDialog
|
||||||
import com.x8bit.bitwarden.ui.platform.components.LoadingDialogState
|
import com.x8bit.bitwarden.ui.platform.components.LoadingDialogState
|
||||||
import com.x8bit.bitwarden.ui.platform.components.OverflowMenuItemData
|
import com.x8bit.bitwarden.ui.platform.components.OverflowMenuItemData
|
||||||
import com.x8bit.bitwarden.ui.platform.components.model.AccountSummary
|
import com.x8bit.bitwarden.ui.platform.components.model.AccountSummary
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||||
import com.x8bit.bitwarden.ui.platform.manager.exit.ExitManager
|
import com.x8bit.bitwarden.ui.platform.manager.exit.ExitManager
|
||||||
import com.x8bit.bitwarden.ui.platform.theme.LocalExitManager
|
import com.x8bit.bitwarden.ui.platform.theme.LocalExitManager
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterType
|
import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterType
|
||||||
|
@ -71,6 +72,7 @@ fun VaultScreen(
|
||||||
onNavigateToVaultEditItemScreen: (vaultItemId: String) -> Unit,
|
onNavigateToVaultEditItemScreen: (vaultItemId: String) -> Unit,
|
||||||
onNavigateToVerificationCodeScreen: () -> Unit,
|
onNavigateToVerificationCodeScreen: () -> Unit,
|
||||||
onNavigateToVaultItemListingScreen: (vaultItemType: VaultItemListingType) -> Unit,
|
onNavigateToVaultItemListingScreen: (vaultItemType: VaultItemListingType) -> Unit,
|
||||||
|
onNavigateToSearchVault: (searchType: SearchType.Vault) -> Unit,
|
||||||
onDimBottomNavBarRequest: (shouldDim: Boolean) -> Unit,
|
onDimBottomNavBarRequest: (shouldDim: Boolean) -> Unit,
|
||||||
exitManager: ExitManager = LocalExitManager.current,
|
exitManager: ExitManager = LocalExitManager.current,
|
||||||
) {
|
) {
|
||||||
|
@ -88,12 +90,7 @@ fun VaultScreen(
|
||||||
|
|
||||||
VaultEvent.NavigateToAddItemScreen -> onNavigateToVaultAddItemScreen()
|
VaultEvent.NavigateToAddItemScreen -> onNavigateToVaultAddItemScreen()
|
||||||
|
|
||||||
VaultEvent.NavigateToVaultSearchScreen -> {
|
VaultEvent.NavigateToVaultSearchScreen -> onNavigateToSearchVault(SearchType.Vault.All)
|
||||||
// TODO Create vault search screen and navigation implementation BIT-213
|
|
||||||
Toast
|
|
||||||
.makeText(context, "Navigate to the vault search screen.", Toast.LENGTH_SHORT)
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
is VaultEvent.NavigateToVerificationCodeScreen -> {
|
is VaultEvent.NavigateToVerificationCodeScreen -> {
|
||||||
onNavigateToVerificationCodeScreen()
|
onNavigateToVerificationCodeScreen()
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
package com.x8bit.bitwarden.ui.platform.feature.search
|
||||||
|
|
||||||
|
import com.x8bit.bitwarden.data.platform.repository.util.bufferedMutableSharedFlow
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||||
|
import io.mockk.every
|
||||||
|
import io.mockk.mockk
|
||||||
|
import kotlinx.coroutines.flow.MutableStateFlow
|
||||||
|
import org.junit.Assert.assertTrue
|
||||||
|
import org.junit.Before
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class SearchScreenTest : BaseComposeTest() {
|
||||||
|
private val mutableEventFlow = bufferedMutableSharedFlow<SearchEvent>()
|
||||||
|
private val mutableStateFlow = MutableStateFlow(DEFAULT_STATE)
|
||||||
|
private val viewModel = mockk<SearchViewModel> {
|
||||||
|
every { eventFlow } returns mutableEventFlow
|
||||||
|
every { stateFlow } returns mutableStateFlow
|
||||||
|
}
|
||||||
|
|
||||||
|
private var onNavigateBackCalled = false
|
||||||
|
|
||||||
|
@Before
|
||||||
|
fun setup() {
|
||||||
|
composeTestRule.setContent {
|
||||||
|
SearchScreen(
|
||||||
|
viewModel = viewModel,
|
||||||
|
onNavigateBack = { onNavigateBackCalled = true },
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `NavigateBack should call onNavigateBack`() {
|
||||||
|
mutableEventFlow.tryEmit(SearchEvent.NavigateBack)
|
||||||
|
assertTrue(onNavigateBackCalled)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val DEFAULT_STATE: SearchState = SearchState(
|
||||||
|
searchType = SearchType.Vault.All,
|
||||||
|
)
|
|
@ -0,0 +1,83 @@
|
||||||
|
package com.x8bit.bitwarden.ui.platform.feature.search
|
||||||
|
|
||||||
|
import androidx.lifecycle.SavedStateHandle
|
||||||
|
import app.cash.turbine.test
|
||||||
|
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||||
|
import kotlinx.coroutines.test.runTest
|
||||||
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
class SearchViewModelTest : BaseViewModelTest() {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `initial state should be correct when not set`() {
|
||||||
|
val viewModel = createViewModel(initialState = null)
|
||||||
|
assertEquals(DEFAULT_STATE, viewModel.stateFlow.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `initial state should be correct when set`() {
|
||||||
|
val state = DEFAULT_STATE.copy(searchType = SearchType.Sends.All)
|
||||||
|
val viewModel = createViewModel(initialState = state)
|
||||||
|
assertEquals(state, viewModel.stateFlow.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `BackClick should emit NavigateBack`() = runTest {
|
||||||
|
val viewModel = createViewModel()
|
||||||
|
viewModel.eventFlow.test {
|
||||||
|
viewModel.trySendAction(SearchAction.BackClick)
|
||||||
|
assertEquals(SearchEvent.NavigateBack, awaitItem())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("CyclomaticComplexMethod")
|
||||||
|
private fun createViewModel(
|
||||||
|
initialState: SearchState? = null,
|
||||||
|
): SearchViewModel = SearchViewModel(
|
||||||
|
SavedStateHandle().apply {
|
||||||
|
set("state", initialState)
|
||||||
|
set(
|
||||||
|
"search_type",
|
||||||
|
when (initialState?.searchType) {
|
||||||
|
SearchType.Sends.All -> "search_type_sends_all"
|
||||||
|
SearchType.Sends.Files -> "search_type_sends_file"
|
||||||
|
SearchType.Sends.Texts -> "search_type_sends_text"
|
||||||
|
SearchType.Vault.All -> "search_type_vault_all"
|
||||||
|
SearchType.Vault.Cards -> "search_type_vault_cards"
|
||||||
|
is SearchType.Vault.Collection -> "search_type_vault_collection"
|
||||||
|
is SearchType.Vault.Folder -> "search_type_vault_folder"
|
||||||
|
SearchType.Vault.Identities -> "search_type_vault_identities"
|
||||||
|
SearchType.Vault.Logins -> "search_type_vault_logins"
|
||||||
|
SearchType.Vault.NoFolder -> "search_type_vault_no_folder"
|
||||||
|
SearchType.Vault.SecureNotes -> "search_type_vault_secure_notes"
|
||||||
|
SearchType.Vault.Trash -> "search_type_vault_trash"
|
||||||
|
null -> "search_type_vault_all"
|
||||||
|
},
|
||||||
|
)
|
||||||
|
set(
|
||||||
|
"search_type_id",
|
||||||
|
when (val searchType = initialState?.searchType) {
|
||||||
|
SearchType.Sends.All -> null
|
||||||
|
SearchType.Sends.Files -> null
|
||||||
|
SearchType.Sends.Texts -> null
|
||||||
|
SearchType.Vault.All -> null
|
||||||
|
SearchType.Vault.Cards -> null
|
||||||
|
is SearchType.Vault.Collection -> searchType.collectionId
|
||||||
|
is SearchType.Vault.Folder -> searchType.folderId
|
||||||
|
SearchType.Vault.Identities -> null
|
||||||
|
SearchType.Vault.Logins -> null
|
||||||
|
SearchType.Vault.NoFolder -> null
|
||||||
|
SearchType.Vault.SecureNotes -> null
|
||||||
|
SearchType.Vault.Trash -> null
|
||||||
|
null -> null
|
||||||
|
},
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private val DEFAULT_STATE: SearchState = SearchState(
|
||||||
|
searchType = SearchType.Vault.All,
|
||||||
|
)
|
|
@ -47,6 +47,8 @@ class VaultUnlockedNavBarScreenTest : BaseComposeTest() {
|
||||||
onNavigateToDeleteAccount = {},
|
onNavigateToDeleteAccount = {},
|
||||||
onNavigateToFolders = {},
|
onNavigateToFolders = {},
|
||||||
onNavigateToPasswordHistory = {},
|
onNavigateToPasswordHistory = {},
|
||||||
|
onNavigateToSearchVault = {},
|
||||||
|
onNavigateToSearchSend = {},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ class SendScreenTest : BaseComposeTest() {
|
||||||
private var onNavigateToNewSendCalled = false
|
private var onNavigateToNewSendCalled = false
|
||||||
private var onNavigateToSendFilesListCalled = false
|
private var onNavigateToSendFilesListCalled = false
|
||||||
private var onNavigateToSendTextListCalled = false
|
private var onNavigateToSendTextListCalled = false
|
||||||
|
private var onNavigateToSendSearchCalled = false
|
||||||
private var onNavigateToEditSendId: String? = null
|
private var onNavigateToEditSendId: String? = null
|
||||||
|
|
||||||
private val intentManager = mockk<IntentManager> {
|
private val intentManager = mockk<IntentManager> {
|
||||||
|
@ -63,6 +64,7 @@ class SendScreenTest : BaseComposeTest() {
|
||||||
onNavigateToEditSend = { onNavigateToEditSendId = it },
|
onNavigateToEditSend = { onNavigateToEditSendId = it },
|
||||||
onNavigateToSendFilesList = { onNavigateToSendFilesListCalled = true },
|
onNavigateToSendFilesList = { onNavigateToSendFilesListCalled = true },
|
||||||
onNavigateToSendTextList = { onNavigateToSendTextListCalled = true },
|
onNavigateToSendTextList = { onNavigateToSendTextListCalled = true },
|
||||||
|
onNavigateToSearchSend = { onNavigateToSendSearchCalled = true },
|
||||||
intentManager = intentManager,
|
intentManager = intentManager,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -93,6 +95,12 @@ class SendScreenTest : BaseComposeTest() {
|
||||||
assertTrue(onNavigateToSendTextListCalled)
|
assertTrue(onNavigateToSendTextListCalled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `on NavigateToSearch should call onNavigateToSendSearch`() {
|
||||||
|
mutableEventFlow.tryEmit(SendEvent.NavigateToSearch)
|
||||||
|
assertTrue(onNavigateToSendSearchCalled)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `on NavigateToAboutSend should call launchUri on intentManager`() {
|
fun `on NavigateToAboutSend should call launchUri on intentManager`() {
|
||||||
mutableEventFlow.tryEmit(SendEvent.NavigateToAboutSend)
|
mutableEventFlow.tryEmit(SendEvent.NavigateToAboutSend)
|
||||||
|
|
|
@ -108,11 +108,11 @@ class SendViewModelTest : BaseViewModelTest() {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `SearchClick should emit ShowToast`() = runTest {
|
fun `SearchClick should emit NavigateToSearch`() = runTest {
|
||||||
val viewModel = createViewModel()
|
val viewModel = createViewModel()
|
||||||
viewModel.eventFlow.test {
|
viewModel.eventFlow.test {
|
||||||
viewModel.trySendAction(SendAction.SearchClick)
|
viewModel.trySendAction(SendAction.SearchClick)
|
||||||
assertEquals(SendEvent.ShowToast("Search Not Implemented".asText()), awaitItem())
|
assertEquals(SendEvent.NavigateToSearch, awaitItem())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ import com.x8bit.bitwarden.ui.platform.base.BaseComposeTest
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||||
import com.x8bit.bitwarden.ui.platform.components.model.IconData
|
import com.x8bit.bitwarden.ui.platform.components.model.IconData
|
||||||
import com.x8bit.bitwarden.ui.platform.components.model.IconRes
|
import com.x8bit.bitwarden.ui.platform.components.model.IconRes
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||||
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
import com.x8bit.bitwarden.ui.platform.manager.intent.IntentManager
|
||||||
import com.x8bit.bitwarden.ui.util.assertNoDialogExists
|
import com.x8bit.bitwarden.ui.util.assertNoDialogExists
|
||||||
import com.x8bit.bitwarden.ui.util.isProgressBar
|
import com.x8bit.bitwarden.ui.util.isProgressBar
|
||||||
|
@ -50,6 +51,7 @@ class VaultItemListingScreenTest : BaseComposeTest() {
|
||||||
private var onNavigateToAddSendScreenCalled = false
|
private var onNavigateToAddSendScreenCalled = false
|
||||||
private var onNavigateToEditSendItemId: String? = null
|
private var onNavigateToEditSendItemId: String? = null
|
||||||
private var onNavigateToVaultItemId: String? = null
|
private var onNavigateToVaultItemId: String? = null
|
||||||
|
private var onNavigateToSearchType: SearchType? = null
|
||||||
|
|
||||||
private val intentManager: IntentManager = mockk {
|
private val intentManager: IntentManager = mockk {
|
||||||
every { shareText(any()) } just runs
|
every { shareText(any()) } just runs
|
||||||
|
@ -72,6 +74,7 @@ class VaultItemListingScreenTest : BaseComposeTest() {
|
||||||
onNavigateToVaultAddItemScreen = { onNavigateToVaultAddItemScreenCalled = true },
|
onNavigateToVaultAddItemScreen = { onNavigateToVaultAddItemScreenCalled = true },
|
||||||
onNavigateToAddSendItem = { onNavigateToAddSendScreenCalled = true },
|
onNavigateToAddSendItem = { onNavigateToAddSendScreenCalled = true },
|
||||||
onNavigateToEditSendItem = { onNavigateToEditSendItemId = it },
|
onNavigateToEditSendItem = { onNavigateToEditSendItemId = it },
|
||||||
|
onNavigateToSearch = { onNavigateToSearchType = it },
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -147,6 +150,13 @@ class VaultItemListingScreenTest : BaseComposeTest() {
|
||||||
assertTrue(onNavigateToAddSendScreenCalled)
|
assertTrue(onNavigateToAddSendScreenCalled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `NavigateToVaultSearchScreen should call onNavigateToSearch`() {
|
||||||
|
val searchType = SearchType.Vault.SecureNotes
|
||||||
|
mutableEventFlow.tryEmit(VaultItemListingEvent.NavigateToSearchScreen(searchType))
|
||||||
|
assertEquals(searchType, onNavigateToSearchType)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `NavigateToSendItem event should call onNavigateToEditSendItemId`() {
|
fun `NavigateToSendItem event should call onNavigateToEditSendItemId`() {
|
||||||
val sendId = "sendId"
|
val sendId = "sendId"
|
||||||
|
|
|
@ -22,6 +22,7 @@ import com.x8bit.bitwarden.data.vault.repository.model.VaultData
|
||||||
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
import com.x8bit.bitwarden.ui.platform.base.BaseViewModelTest
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
import com.x8bit.bitwarden.ui.platform.base.util.asText
|
||||||
import com.x8bit.bitwarden.ui.platform.base.util.concat
|
import com.x8bit.bitwarden.ui.platform.base.util.concat
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.model.ListingItemOverflowAction
|
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.model.ListingItemOverflowAction
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.util.createMockDisplayItemForCipher
|
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.util.createMockDisplayItemForCipher
|
||||||
import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterType
|
import com.x8bit.bitwarden.ui.vault.feature.vault.model.VaultFilterType
|
||||||
|
@ -106,10 +107,11 @@ class VaultItemListingViewModelTest : BaseViewModelTest() {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `SearchIconClick should emit NavigateToVaultSearchScreen`() = runTest {
|
fun `SearchIconClick should emit NavigateToVaultSearchScreen`() = runTest {
|
||||||
|
val searchType = SearchType.Vault.Logins
|
||||||
val viewModel = createVaultItemListingViewModel()
|
val viewModel = createVaultItemListingViewModel()
|
||||||
viewModel.eventFlow.test {
|
viewModel.eventFlow.test {
|
||||||
viewModel.actionChannel.trySend(VaultItemListingsAction.SearchIconClick)
|
viewModel.actionChannel.trySend(VaultItemListingsAction.SearchIconClick)
|
||||||
assertEquals(VaultItemListingEvent.NavigateToVaultSearchScreen, awaitItem())
|
assertEquals(VaultItemListingEvent.NavigateToSearchScreen(searchType), awaitItem())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,111 @@
|
||||||
|
package com.x8bit.bitwarden.ui.vault.feature.itemlisting.util
|
||||||
|
|
||||||
|
import com.x8bit.bitwarden.ui.platform.feature.search.model.SearchType
|
||||||
|
import com.x8bit.bitwarden.ui.vault.feature.itemlisting.VaultItemListingState
|
||||||
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
|
class VaultItemListingStateExtensionsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `toSearchType should return Texts when item type is SendText`() {
|
||||||
|
val expected = SearchType.Sends.Texts
|
||||||
|
val itemType = VaultItemListingState.ItemListingType.Send.SendText
|
||||||
|
|
||||||
|
val result = itemType.toSearchType()
|
||||||
|
|
||||||
|
assertEquals(expected, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `toSearchType should return Files when item type is SendFile`() {
|
||||||
|
val expected = SearchType.Sends.Files
|
||||||
|
val itemType = VaultItemListingState.ItemListingType.Send.SendFile
|
||||||
|
|
||||||
|
val result = itemType.toSearchType()
|
||||||
|
|
||||||
|
assertEquals(expected, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `toSearchType should return Logins when item type is Login`() {
|
||||||
|
val expected = SearchType.Vault.Logins
|
||||||
|
val itemType = VaultItemListingState.ItemListingType.Vault.Login
|
||||||
|
|
||||||
|
val result = itemType.toSearchType()
|
||||||
|
|
||||||
|
assertEquals(expected, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `toSearchType should return Card when item type is Card`() {
|
||||||
|
val expected = SearchType.Vault.Cards
|
||||||
|
val itemType = VaultItemListingState.ItemListingType.Vault.Card
|
||||||
|
|
||||||
|
val result = itemType.toSearchType()
|
||||||
|
|
||||||
|
assertEquals(expected, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `toSearchType should return Identities when item type is Identity`() {
|
||||||
|
val expected = SearchType.Vault.Identities
|
||||||
|
val itemType = VaultItemListingState.ItemListingType.Vault.Identity
|
||||||
|
|
||||||
|
val result = itemType.toSearchType()
|
||||||
|
|
||||||
|
assertEquals(expected, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `toSearchType should return SecureNotes when item type is SecureNote`() {
|
||||||
|
val expected = SearchType.Vault.SecureNotes
|
||||||
|
val itemType = VaultItemListingState.ItemListingType.Vault.SecureNote
|
||||||
|
|
||||||
|
val result = itemType.toSearchType()
|
||||||
|
|
||||||
|
assertEquals(expected, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `toSearchType should return Trash when item type is Trash`() {
|
||||||
|
val expected = SearchType.Vault.Trash
|
||||||
|
val itemType = VaultItemListingState.ItemListingType.Vault.Trash
|
||||||
|
|
||||||
|
val result = itemType.toSearchType()
|
||||||
|
|
||||||
|
assertEquals(expected, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `toSearchType should return Folder when item type is Folder with an ID`() {
|
||||||
|
val folderId = "folderId"
|
||||||
|
val expected = SearchType.Vault.Folder(folderId)
|
||||||
|
val itemType = VaultItemListingState.ItemListingType.Vault.Folder(folderId)
|
||||||
|
|
||||||
|
val result = itemType.toSearchType()
|
||||||
|
|
||||||
|
assertEquals(expected, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `toSearchType should return NoFolder when item type is Folder without an ID`() {
|
||||||
|
val expected = SearchType.Vault.NoFolder
|
||||||
|
val itemType = VaultItemListingState.ItemListingType.Vault.Folder(null)
|
||||||
|
|
||||||
|
val result = itemType.toSearchType()
|
||||||
|
|
||||||
|
assertEquals(expected, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `toSearchType should return Collection when item type is Collection`() {
|
||||||
|
val collectionId = "collectionId"
|
||||||
|
val expected = SearchType.Vault.Collection(collectionId)
|
||||||
|
val itemType = VaultItemListingState.ItemListingType.Vault.Collection(collectionId)
|
||||||
|
|
||||||
|
val result = itemType.toSearchType()
|
||||||
|
|
||||||
|
assertEquals(expected, result)
|
||||||
|
}
|
||||||
|
}
|
|
@ -61,6 +61,7 @@ class VaultScreenTest : BaseComposeTest() {
|
||||||
private var onNavigateToVaultItemListingType: VaultItemListingType? = null
|
private var onNavigateToVaultItemListingType: VaultItemListingType? = null
|
||||||
private var onDimBottomNavBarRequestCalled = false
|
private var onDimBottomNavBarRequestCalled = false
|
||||||
private var onNavigateToVerificationCodeScreen = false
|
private var onNavigateToVerificationCodeScreen = false
|
||||||
|
private var onNavigateToSearchScreen = false
|
||||||
private val exitManager = mockk<ExitManager>(relaxed = true)
|
private val exitManager = mockk<ExitManager>(relaxed = true)
|
||||||
|
|
||||||
private val mutableEventFlow = bufferedMutableSharedFlow<VaultEvent>()
|
private val mutableEventFlow = bufferedMutableSharedFlow<VaultEvent>()
|
||||||
|
@ -81,6 +82,7 @@ class VaultScreenTest : BaseComposeTest() {
|
||||||
onNavigateToVaultItemListingScreen = { onNavigateToVaultItemListingType = it },
|
onNavigateToVaultItemListingScreen = { onNavigateToVaultItemListingType = it },
|
||||||
onDimBottomNavBarRequest = { onDimBottomNavBarRequestCalled = true },
|
onDimBottomNavBarRequest = { onDimBottomNavBarRequestCalled = true },
|
||||||
onNavigateToVerificationCodeScreen = { onNavigateToVerificationCodeScreen = true },
|
onNavigateToVerificationCodeScreen = { onNavigateToVerificationCodeScreen = true },
|
||||||
|
onNavigateToSearchVault = { onNavigateToSearchScreen = true },
|
||||||
exitManager = exitManager,
|
exitManager = exitManager,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -586,6 +588,12 @@ class VaultScreenTest : BaseComposeTest() {
|
||||||
assertTrue(onNavigateToVaultAddItemScreenCalled)
|
assertTrue(onNavigateToVaultAddItemScreenCalled)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `NavigateToVaultSearchScreen event should call onNavigateToSearchScreen`() {
|
||||||
|
mutableEventFlow.tryEmit(VaultEvent.NavigateToVaultSearchScreen)
|
||||||
|
assertTrue(onNavigateToSearchScreen)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `NavigateToVaultItem event should call onNavigateToVaultItemScreen`() {
|
fun `NavigateToVaultItem event should call onNavigateToVaultItemScreen`() {
|
||||||
val id = "id4321"
|
val id = "id4321"
|
||||||
|
|
Loading…
Reference in a new issue