mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 15:15:34 +03:00
Add the UI for the overflow menu (#570)
This commit is contained in:
parent
e84e69b666
commit
0aa24d73d9
4 changed files with 244 additions and 0 deletions
|
@ -25,11 +25,14 @@ import com.x8bit.bitwarden.ui.platform.components.BitwardenBasicDialog
|
|||
import com.x8bit.bitwarden.ui.platform.components.BitwardenErrorContent
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenLoadingContent
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenLoadingDialog
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenOverflowActionItem
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenScaffold
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenTextButton
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenTopAppBar
|
||||
import com.x8bit.bitwarden.ui.platform.components.LoadingDialogState
|
||||
import com.x8bit.bitwarden.ui.platform.components.OverflowMenuItemData
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.addsend.handlers.AddSendHandlers
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
/**
|
||||
* Displays new send UX.
|
||||
|
@ -86,6 +89,40 @@ fun AddSendScreen(
|
|||
{ viewModel.trySendAction(AddSendAction.SaveClick) }
|
||||
},
|
||||
)
|
||||
if (!state.isAddMode) {
|
||||
BitwardenOverflowActionItem(
|
||||
menuItemDataList = persistentListOf(
|
||||
OverflowMenuItemData(
|
||||
text = stringResource(id = R.string.remove_password),
|
||||
onClick = remember(viewModel) {
|
||||
{
|
||||
viewModel.trySendAction(
|
||||
AddSendAction.RemovePasswordClick,
|
||||
)
|
||||
}
|
||||
},
|
||||
),
|
||||
OverflowMenuItemData(
|
||||
text = stringResource(id = R.string.copy_link),
|
||||
onClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(AddSendAction.CopyLinkClick) }
|
||||
},
|
||||
),
|
||||
OverflowMenuItemData(
|
||||
text = stringResource(id = R.string.share_link),
|
||||
onClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(AddSendAction.ShareLinkClick) }
|
||||
},
|
||||
),
|
||||
OverflowMenuItemData(
|
||||
text = stringResource(id = R.string.delete),
|
||||
onClick = remember(viewModel) {
|
||||
{ viewModel.trySendAction(AddSendAction.DeleteClick) }
|
||||
},
|
||||
),
|
||||
),
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
},
|
||||
|
|
|
@ -93,6 +93,10 @@ class AddSendViewModel @Inject constructor(
|
|||
}
|
||||
|
||||
override fun handleAction(action: AddSendAction): Unit = when (action) {
|
||||
AddSendAction.CopyLinkClick -> handleCopyLinkClick()
|
||||
AddSendAction.DeleteClick -> handleDeleteClick()
|
||||
AddSendAction.RemovePasswordClick -> handleRemovePasswordClick()
|
||||
AddSendAction.ShareLinkClick -> handleShareLinkClick()
|
||||
is AddSendAction.CloseClick -> handleCloseClick()
|
||||
is AddSendAction.DeletionDateChange -> handleDeletionDateChange(action)
|
||||
is AddSendAction.ExpirationDateChange -> handleExpirationDateChange(action)
|
||||
|
@ -150,6 +154,26 @@ class AddSendViewModel @Inject constructor(
|
|||
}
|
||||
}
|
||||
|
||||
private fun handleCopyLinkClick() {
|
||||
// TODO Add copy link support (BIT-1435)
|
||||
sendEvent(AddSendEvent.ShowToast("Not yet implemented"))
|
||||
}
|
||||
|
||||
private fun handleDeleteClick() {
|
||||
// TODO Add deletion support (BIT-1435)
|
||||
sendEvent(AddSendEvent.ShowToast("Not yet implemented"))
|
||||
}
|
||||
|
||||
private fun handleRemovePasswordClick() {
|
||||
// TODO Add remove password support (BIT-1435)
|
||||
sendEvent(AddSendEvent.ShowToast("Not yet implemented"))
|
||||
}
|
||||
|
||||
private fun handleShareLinkClick() {
|
||||
// TODO Add share link support (BIT-1435)
|
||||
sendEvent(AddSendEvent.ShowToast("Not yet implemented"))
|
||||
}
|
||||
|
||||
private fun handlePasswordChange(action: AddSendAction.PasswordChange) {
|
||||
updateCommonContent {
|
||||
it.copy(passwordInput = action.input)
|
||||
|
@ -348,6 +372,11 @@ data class AddSendState(
|
|||
is AddSendType.EditItem -> R.string.edit_send.asText()
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper to determine if the UI should display the content in add send mode.
|
||||
*/
|
||||
val isAddMode: Boolean get() = addSendType is AddSendType.AddItem
|
||||
|
||||
/**
|
||||
* Represents the specific view states for the [AddSendScreen].
|
||||
*/
|
||||
|
@ -463,6 +492,26 @@ sealed class AddSendEvent {
|
|||
*/
|
||||
sealed class AddSendAction {
|
||||
|
||||
/**
|
||||
* User clicked the remove password button.
|
||||
*/
|
||||
data object RemovePasswordClick : AddSendAction()
|
||||
|
||||
/**
|
||||
* User clicked the copy link button.
|
||||
*/
|
||||
data object CopyLinkClick : AddSendAction()
|
||||
|
||||
/**
|
||||
* User clicked the share link button.
|
||||
*/
|
||||
data object ShareLinkClick : AddSendAction()
|
||||
|
||||
/**
|
||||
* User clicked the delete button.
|
||||
*/
|
||||
data object DeleteClick : AddSendAction()
|
||||
|
||||
/**
|
||||
* User clicked the close button.
|
||||
*/
|
||||
|
|
|
@ -9,6 +9,8 @@ import androidx.compose.ui.test.filterToOne
|
|||
import androidx.compose.ui.test.hasAnyAncestor
|
||||
import androidx.compose.ui.test.hasSetTextAction
|
||||
import androidx.compose.ui.test.isDialog
|
||||
import androidx.compose.ui.test.isDisplayed
|
||||
import androidx.compose.ui.test.isPopup
|
||||
import androidx.compose.ui.test.onAllNodesWithText
|
||||
import androidx.compose.ui.test.onNodeWithContentDescription
|
||||
import androidx.compose.ui.test.onNodeWithText
|
||||
|
@ -89,6 +91,110 @@ class AddSendScreenTest : BaseComposeTest() {
|
|||
verify { viewModel.trySendAction(AddSendAction.SaveClick) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on overflow button click should display overflow menu`() {
|
||||
mutableStateFlow.value = DEFAULT_STATE.copy(
|
||||
addSendType = AddSendType.EditItem(sendItemId = "sendId"),
|
||||
)
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription("More")
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Remove password")
|
||||
.assert(hasAnyAncestor(isPopup()))
|
||||
.isDisplayed()
|
||||
composeTestRule
|
||||
.onNodeWithText("Copy link")
|
||||
.assert(hasAnyAncestor(isPopup()))
|
||||
.isDisplayed()
|
||||
composeTestRule
|
||||
.onNodeWithText("Share link")
|
||||
.assert(hasAnyAncestor(isPopup()))
|
||||
.isDisplayed()
|
||||
composeTestRule
|
||||
.onNodeWithText("Delete")
|
||||
.assert(hasAnyAncestor(isPopup()))
|
||||
.isDisplayed()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on overflow remove password button click should send RemovePasswordClick`() {
|
||||
mutableStateFlow.value = DEFAULT_STATE.copy(
|
||||
addSendType = AddSendType.EditItem(sendItemId = "sendId"),
|
||||
)
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription("More")
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Remove password")
|
||||
.performClick()
|
||||
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(AddSendAction.RemovePasswordClick)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on overflow remove Share link button click should send ShareLinkClick`() {
|
||||
mutableStateFlow.value = DEFAULT_STATE.copy(
|
||||
addSendType = AddSendType.EditItem(sendItemId = "sendId"),
|
||||
)
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription("More")
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Share link")
|
||||
.performClick()
|
||||
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(AddSendAction.ShareLinkClick)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on overflow remove Delete button click should send DeleteClick`() {
|
||||
mutableStateFlow.value = DEFAULT_STATE.copy(
|
||||
addSendType = AddSendType.EditItem(sendItemId = "sendId"),
|
||||
)
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription("More")
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Delete")
|
||||
.performClick()
|
||||
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(AddSendAction.DeleteClick)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on overflow remove Copy link button click should send CopyLinkClick`() {
|
||||
mutableStateFlow.value = DEFAULT_STATE.copy(
|
||||
addSendType = AddSendType.EditItem(sendItemId = "sendId"),
|
||||
)
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithContentDescription("More")
|
||||
.performClick()
|
||||
|
||||
composeTestRule
|
||||
.onNodeWithText("Copy link")
|
||||
.performClick()
|
||||
|
||||
verify(exactly = 1) {
|
||||
viewModel.trySendAction(AddSendAction.CopyLinkClick)
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `on name input change should send NameChange`() {
|
||||
composeTestRule
|
||||
|
|
|
@ -168,6 +168,58 @@ class AddSendViewModelTest : BaseViewModelTest() {
|
|||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `CopyLinkClick should send ShowToast`() = runTest {
|
||||
val viewModel = createViewModel(
|
||||
state = DEFAULT_STATE.copy(addSendType = AddSendType.EditItem("sendId")),
|
||||
addSendType = AddSendType.EditItem("sendId"),
|
||||
)
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(AddSendAction.CopyLinkClick)
|
||||
assertEquals(AddSendEvent.ShowToast("Not yet implemented"), awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `DeleteClick should send ShowToast`() = runTest {
|
||||
val viewModel = createViewModel(
|
||||
state = DEFAULT_STATE.copy(addSendType = AddSendType.EditItem("sendId")),
|
||||
addSendType = AddSendType.EditItem("sendId"),
|
||||
)
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(AddSendAction.DeleteClick)
|
||||
assertEquals(AddSendEvent.ShowToast("Not yet implemented"), awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `RemovePasswordClick should send ShowToast`() = runTest {
|
||||
val viewModel = createViewModel(
|
||||
state = DEFAULT_STATE.copy(addSendType = AddSendType.EditItem("sendId")),
|
||||
addSendType = AddSendType.EditItem("sendId"),
|
||||
)
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(AddSendAction.RemovePasswordClick)
|
||||
assertEquals(AddSendEvent.ShowToast("Not yet implemented"), awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ShareLinkClick should send ShowToast`() = runTest {
|
||||
val viewModel = createViewModel(
|
||||
state = DEFAULT_STATE.copy(addSendType = AddSendType.EditItem("sendId")),
|
||||
addSendType = AddSendType.EditItem("sendId"),
|
||||
)
|
||||
|
||||
viewModel.eventFlow.test {
|
||||
viewModel.trySendAction(AddSendAction.ShareLinkClick)
|
||||
assertEquals(AddSendEvent.ShowToast("Not yet implemented"), awaitItem())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `DismissDialogClick should clear the dialog state`() {
|
||||
val viewModel = createViewModel(
|
||||
|
|
Loading…
Reference in a new issue