Add the overflow menu to the send screen (#469)

This commit is contained in:
David Perez
2024-06-20 17:08:07 +01:00
committed by Álison Fernandes
parent cf2e87c9f5
commit 7a8da67944
4 changed files with 223 additions and 28 deletions
@@ -16,40 +16,58 @@ import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.IntSize
import androidx.core.net.toUri
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.x8bit.bitwarden.R
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
import com.x8bit.bitwarden.ui.platform.base.util.IntentHandler
import com.x8bit.bitwarden.ui.platform.components.BitwardenMediumTopAppBar
import com.x8bit.bitwarden.ui.platform.components.BitwardenOverflowActionItem
import com.x8bit.bitwarden.ui.platform.components.BitwardenScaffold
import com.x8bit.bitwarden.ui.platform.components.BitwardenSearchActionItem
import com.x8bit.bitwarden.ui.platform.components.OverflowMenuItemData
import kotlinx.collections.immutable.persistentListOf
/**
* UI for the send screen.
*/
@Suppress("LongMethod")
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SendScreen(
onNavigateNewSend: () -> Unit,
viewModel: SendViewModel = hiltViewModel(),
intentHandler: IntentHandler = IntentHandler(context = LocalContext.current),
) {
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
val scrollBehavior =
TopAppBarDefaults.exitUntilCollapsedScrollBehavior(rememberTopAppBarState())
val context = LocalContext.current
EventsEffect(viewModel = viewModel) { event ->
when (event) {
is SendEvent.NavigateNewSend -> onNavigateNewSend()
is SendEvent.ShowToast -> Toast
.makeText(context, event.messsage(context.resources), Toast.LENGTH_SHORT)
.show()
is SendEvent.NavigateToAboutSend -> {
intentHandler.launchUri("https://bitwarden.com/products/send".toUri())
}
is SendEvent.ShowToast -> {
Toast
.makeText(context, event.message(context.resources), Toast.LENGTH_SHORT)
.show()
}
}
}
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(
state = rememberTopAppBarState(),
)
BitwardenScaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = {
BitwardenMediumTopAppBar(
title = stringResource(id = R.string.send),
@@ -61,6 +79,28 @@ fun SendScreen(
{ viewModel.trySendAction(SendAction.SearchClick) }
},
)
BitwardenOverflowActionItem(
menuItemDataList = persistentListOf(
OverflowMenuItemData(
text = stringResource(id = R.string.sync),
onClick = remember(viewModel) {
{ viewModel.trySendAction(SendAction.SyncClick) }
},
),
OverflowMenuItemData(
text = stringResource(id = R.string.lock),
onClick = remember(viewModel) {
{ viewModel.trySendAction(SendAction.LockClick) }
},
),
OverflowMenuItemData(
text = stringResource(id = R.string.about_send),
onClick = remember(viewModel) {
{ viewModel.trySendAction(SendAction.AboutSendClick) }
},
),
),
)
},
)
},
@@ -86,7 +126,7 @@ fun SendScreen(
}
},
) { padding ->
Box(Modifier.padding(padding)) {
Box(modifier = Modifier.padding(padding)) {
when (state) {
SendState.Empty -> SendEmpty(
remember(viewModel) {
@@ -2,13 +2,11 @@ package com.x8bit.bitwarden.ui.tools.feature.send
import android.os.Parcelable
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import com.x8bit.bitwarden.data.vault.repository.VaultRepository
import com.x8bit.bitwarden.ui.platform.base.BaseViewModel
import com.x8bit.bitwarden.ui.platform.base.util.Text
import com.x8bit.bitwarden.ui.platform.base.util.asText
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.parcelize.Parcelize
import javax.inject.Inject
@@ -20,19 +18,29 @@ private const val KEY_STATE = "state"
@HiltViewModel
class SendViewModel @Inject constructor(
savedStateHandle: SavedStateHandle,
private val vaultRepo: VaultRepository,
) : BaseViewModel<SendState, SendEvent, SendAction>(
// We load the state from the savedStateHandle for testing purposes.
initialState = savedStateHandle[KEY_STATE] ?: SendState.Empty,
) {
init {
stateFlow
.onEach { savedStateHandle[KEY_STATE] = it }
.launchIn(viewModelScope)
override fun handleAction(action: SendAction): Unit = when (action) {
SendAction.AboutSendClick -> handleAboutSendClick()
SendAction.AddSendClick -> handleAddSendClick()
SendAction.LockClick -> handleLockClick()
SendAction.SearchClick -> handleSearchClick()
SendAction.SyncClick -> handleSyncClick()
}
override fun handleAction(action: SendAction): Unit = when (action) {
SendAction.AddSendClick -> handleSendClick()
SendAction.SearchClick -> handleSearchClick()
private fun handleAboutSendClick() {
sendEvent(SendEvent.NavigateToAboutSend)
}
private fun handleAddSendClick() {
sendEvent(SendEvent.NavigateNewSend)
}
private fun handleLockClick() {
vaultRepo.lockVaultForCurrentUser()
}
private fun handleSearchClick() {
@@ -40,7 +48,10 @@ class SendViewModel @Inject constructor(
sendEvent(SendEvent.ShowToast("Search Not Implemented".asText()))
}
private fun handleSendClick() = sendEvent(SendEvent.NavigateNewSend)
private fun handleSyncClick() {
// TODO: Add loading dialog state BIT-481
vaultRepo.sync()
}
}
/**
@@ -58,15 +69,30 @@ sealed class SendState : Parcelable {
* Models actions for the send screen.
*/
sealed class SendAction {
/**
* User clicked the about send button.
*/
data object AboutSendClick : SendAction()
/**
* User clicked add a send.
*/
data object AddSendClick : SendAction()
/**
* User clicked the lock button.
*/
data object LockClick : SendAction()
/**
* User clicked search button.
*/
data object SearchClick : SendAction()
/**
* User clicked the sync button.
*/
data object SyncClick : SendAction()
}
/**
@@ -78,8 +104,13 @@ sealed class SendEvent {
*/
data object NavigateNewSend : SendEvent()
/**
* Navigate to the about send screen.
*/
data object NavigateToAboutSend : SendEvent()
/**
* Show a toast to the user.
*/
data class ShowToast(val messsage: Text) : SendEvent()
data class ShowToast(val message: Text) : SendEvent()
}