mirror of
https://github.com/bitwarden/android.git
synced 2026-06-08 08:06:32 -05:00
Populate the send screen with real data (#488)
This commit is contained in:
committed by
Álison Fernandes
parent
da53c72a61
commit
15fcfce0b2
@@ -1,5 +1,6 @@
|
||||
package com.x8bit.bitwarden.ui.platform.base.util
|
||||
|
||||
import androidx.compose.material3.DividerDefaults
|
||||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
@@ -7,6 +8,11 @@ import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.drawBehind
|
||||
import androidx.compose.ui.draw.drawWithCache
|
||||
import androidx.compose.ui.geometry.Offset
|
||||
import androidx.compose.ui.graphics.Color
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
|
||||
|
||||
/**
|
||||
@@ -31,3 +37,35 @@ fun Modifier.scrolledContainerBackground(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a [Modifier] extension for drawing a divider at the bottom of the composable.
|
||||
*/
|
||||
@OmitFromCoverage
|
||||
@Stable
|
||||
@Composable
|
||||
fun Modifier.bottomDivider(
|
||||
paddingStart: Dp = 0.dp,
|
||||
paddingEnd: Dp = 0.dp,
|
||||
thickness: Dp = DividerDefaults.Thickness,
|
||||
color: Color = DividerDefaults.color,
|
||||
enabled: Boolean = true,
|
||||
): Modifier = drawWithCache {
|
||||
onDrawWithContent {
|
||||
drawContent()
|
||||
if (enabled) {
|
||||
drawLine(
|
||||
color = color,
|
||||
strokeWidth = thickness.toPx(),
|
||||
start = Offset(
|
||||
x = paddingStart.toPx(),
|
||||
y = size.height - thickness.toPx() / 2,
|
||||
),
|
||||
end = Offset(
|
||||
x = size.width - paddingEnd.toPx(),
|
||||
y = size.height - thickness.toPx() / 2,
|
||||
),
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
package com.x8bit.bitwarden.ui.platform.components
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.bottomDivider
|
||||
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||
|
||||
/**
|
||||
* A reusable composable function that displays a group item.
|
||||
* The list item consists of a start icon, a label, a supporting label and an optional divider.
|
||||
*
|
||||
* @param label The main text label to be displayed in the group item.
|
||||
* @param supportingLabel The secondary supporting text label to be displayed beside the label.
|
||||
* @param startIcon The [Painter] object used to draw the icon at the start of the group item.
|
||||
* @param onClick A lambda function that is invoked when the group is clicked.
|
||||
* @param modifier The [Modifier] to be applied to the [Row] composable that holds the list item.
|
||||
* @param showDivider Indicates whether the divider should be shown or not.
|
||||
*/
|
||||
@Composable
|
||||
fun BitwardenGroupItem(
|
||||
label: String,
|
||||
supportingLabel: String,
|
||||
startIcon: Painter,
|
||||
onClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
showDivider: Boolean = true,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = onClick,
|
||||
)
|
||||
.bottomDivider(
|
||||
enabled = showDivider,
|
||||
paddingStart = 16.dp,
|
||||
)
|
||||
.padding(
|
||||
top = 16.dp,
|
||||
bottom = 16.dp,
|
||||
end = 8.dp,
|
||||
)
|
||||
.then(modifier),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
) {
|
||||
Icon(
|
||||
painter = startIcon,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onSurface,
|
||||
modifier = Modifier.size(24.dp),
|
||||
)
|
||||
|
||||
Text(
|
||||
text = label,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
modifier = Modifier.weight(1f),
|
||||
)
|
||||
|
||||
Text(
|
||||
text = supportingLabel,
|
||||
style = MaterialTheme.typography.labelSmall,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_navigate_next),
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.size(24.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun BitwardenGroupItem_preview() {
|
||||
BitwardenTheme {
|
||||
BitwardenGroupItem(
|
||||
label = "Sample Label",
|
||||
supportingLabel = "5",
|
||||
startIcon = painterResource(id = R.drawable.ic_send_text),
|
||||
onClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
package com.x8bit.bitwarden.ui.platform.components
|
||||
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.defaultMinSize
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.size
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.IconButton
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.setValue
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||
|
||||
/**
|
||||
* A Composable function that displays a row item.
|
||||
*
|
||||
* @param label The primary text label to display for the item.
|
||||
* @param supportingLabel An secondary text label to display beneath the label.
|
||||
* @param startIcon The [Painter] object used to draw the icon at the start of the item.
|
||||
* @param onClick The lambda to be invoked when the item is clicked.
|
||||
* @param modifier An optional [Modifier] for this Composable, defaulting to an empty Modifier.
|
||||
* This allows the caller to specify things like padding, size, etc.
|
||||
* @param selectionDataList A list of all the selection items to be displayed in the overflow
|
||||
* dialog.
|
||||
*/
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
fun BitwardenListItem(
|
||||
label: String,
|
||||
supportingLabel: String,
|
||||
startIcon: Painter,
|
||||
onClick: () -> Unit,
|
||||
selectionDataList: List<SelectionItemData>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
var shouldShowDialog by remember { mutableStateOf(false) }
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.clickable(
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
|
||||
onClick = onClick,
|
||||
)
|
||||
.defaultMinSize(minHeight = 72.dp)
|
||||
.padding(vertical = 8.dp)
|
||||
.then(modifier),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.spacedBy(16.dp),
|
||||
) {
|
||||
Icon(
|
||||
painter = startIcon,
|
||||
contentDescription = null,
|
||||
tint = MaterialTheme.colorScheme.onSurface,
|
||||
modifier = Modifier.size(24.dp),
|
||||
)
|
||||
|
||||
Column(modifier = Modifier.weight(1f)) {
|
||||
Text(
|
||||
text = label,
|
||||
style = MaterialTheme.typography.bodyLarge,
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
|
||||
Text(
|
||||
text = supportingLabel,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
color = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
)
|
||||
}
|
||||
|
||||
IconButton(
|
||||
onClick = { shouldShowDialog = true },
|
||||
) {
|
||||
Icon(
|
||||
painter = painterResource(id = R.drawable.ic_more_horizontal),
|
||||
contentDescription = stringResource(id = R.string.options),
|
||||
tint = MaterialTheme.colorScheme.onSurfaceVariant,
|
||||
modifier = Modifier.size(24.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
if (shouldShowDialog) {
|
||||
BitwardenSelectionDialog(
|
||||
title = label,
|
||||
onDismissRequest = { shouldShowDialog = false },
|
||||
selectionItems = {
|
||||
selectionDataList.forEach {
|
||||
BitwardenBasicDialogRow(
|
||||
text = it.text,
|
||||
onClick = {
|
||||
shouldShowDialog = false
|
||||
it.onClick()
|
||||
},
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for the an individual selection item's data.
|
||||
*/
|
||||
data class SelectionItemData(
|
||||
val text: String,
|
||||
val onClick: () -> Unit,
|
||||
)
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun BitwardenListItem_preview() {
|
||||
BitwardenTheme {
|
||||
BitwardenListItem(
|
||||
label = "Sample Label",
|
||||
supportingLabel = "Jan 3, 2024, 10:35 AM",
|
||||
startIcon = painterResource(id = R.drawable.ic_send_text),
|
||||
onClick = {},
|
||||
selectionDataList = emptyList(),
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -6,31 +6,89 @@ import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenGroupItem
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenListHeaderText
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenListHeaderTextWithSupportLabel
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.handlers.SendHandlers
|
||||
|
||||
/**
|
||||
* Content view for the [SendScreen].
|
||||
*/
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
fun SendContent(
|
||||
state: SendState.ViewState.Content,
|
||||
sendHandlers: SendHandlers,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
LazyColumn(modifier = modifier) {
|
||||
item {
|
||||
// TODO: Populate with real data BIT-481
|
||||
Text(
|
||||
text = "Not yet implemented",
|
||||
color = MaterialTheme.colorScheme.onSurface,
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
textAlign = TextAlign.Center,
|
||||
BitwardenListHeaderText(
|
||||
label = stringResource(id = R.string.types),
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 16.dp)
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
BitwardenGroupItem(
|
||||
label = stringResource(id = R.string.type_text),
|
||||
supportingLabel = state.textTypeCount.toString(),
|
||||
startIcon = painterResource(id = R.drawable.ic_send_text),
|
||||
onClick = sendHandlers.onTextTypeClick,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
BitwardenGroupItem(
|
||||
label = stringResource(id = R.string.type_file),
|
||||
supportingLabel = state.fileTypeCount.toString(),
|
||||
startIcon = painterResource(id = R.drawable.ic_send_file),
|
||||
onClick = sendHandlers.onFileTypeClick,
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
BitwardenListHeaderTextWithSupportLabel(
|
||||
label = stringResource(id = R.string.all_sends),
|
||||
supportingLabel = state.sendItems.size.toString(),
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp),
|
||||
)
|
||||
}
|
||||
|
||||
items(state.sendItems) {
|
||||
SendListItem(
|
||||
startIcon = painterResource(id = it.type.iconRes),
|
||||
label = it.name,
|
||||
supportingLabel = it.deletionDate,
|
||||
onClick = { sendHandlers.onSendClick(it) },
|
||||
onCopyClick = { sendHandlers.onCopySendClick(it) },
|
||||
onEditClick = { sendHandlers.onEditSendClick(it) },
|
||||
onShareClick = { sendHandlers.onShareSendClick(it) },
|
||||
modifier = Modifier
|
||||
.padding(
|
||||
start = 16.dp,
|
||||
// There is some built-in padding to the menu button that makes up
|
||||
// the visual difference here.
|
||||
end = 12.dp,
|
||||
)
|
||||
.fillMaxWidth(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
package com.x8bit.bitwarden.ui.tools.feature.send
|
||||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.painter.Painter
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.tooling.preview.Preview
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenListItem
|
||||
import com.x8bit.bitwarden.ui.platform.components.SelectionItemData
|
||||
import com.x8bit.bitwarden.ui.platform.theme.BitwardenTheme
|
||||
|
||||
/**
|
||||
* A Composable function that displays a row send item.
|
||||
*
|
||||
* @param label The primary text label to display for the item.
|
||||
* @param supportingLabel An secondary text label to display beneath the label.
|
||||
* @param startIcon The [Painter] object used to draw the icon at the start of the item.
|
||||
* @param onClick The lambda to be invoked when the item is clicked.
|
||||
* @param onEditClick The lambda to be invoked when the edit option is clicked from the menu.
|
||||
* @param onCopyClick The lambda to be invoked when the copy option is clicked from the menu.
|
||||
* @param onShareClick The lambda to be invoked when the share option is clicked from the menu.
|
||||
* @param modifier An optional [Modifier] for this Composable, defaulting to an empty Modifier.
|
||||
* This allows the caller to specify things like padding, size, etc.
|
||||
*/
|
||||
@Suppress("LongMethod")
|
||||
@Composable
|
||||
fun SendListItem(
|
||||
label: String,
|
||||
supportingLabel: String,
|
||||
startIcon: Painter,
|
||||
onClick: () -> Unit,
|
||||
onEditClick: () -> Unit,
|
||||
onCopyClick: () -> Unit,
|
||||
onShareClick: () -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
BitwardenListItem(
|
||||
label = label,
|
||||
supportingLabel = supportingLabel,
|
||||
startIcon = startIcon,
|
||||
onClick = onClick,
|
||||
selectionDataList = listOf(
|
||||
SelectionItemData(
|
||||
text = stringResource(id = R.string.edit),
|
||||
onClick = onEditClick,
|
||||
),
|
||||
SelectionItemData(
|
||||
text = stringResource(id = R.string.copy_link),
|
||||
onClick = onCopyClick,
|
||||
),
|
||||
SelectionItemData(
|
||||
text = stringResource(id = R.string.share_link),
|
||||
onClick = onShareClick,
|
||||
),
|
||||
),
|
||||
modifier = modifier,
|
||||
)
|
||||
}
|
||||
|
||||
@Preview(showBackground = true)
|
||||
@Composable
|
||||
private fun SendListItem_preview() {
|
||||
BitwardenTheme {
|
||||
SendListItem(
|
||||
label = "Sample Label",
|
||||
supportingLabel = "Jan 3, 2024, 10:35 AM",
|
||||
startIcon = painterResource(id = R.drawable.ic_send_text),
|
||||
onClick = {},
|
||||
onCopyClick = {},
|
||||
onEditClick = {},
|
||||
onShareClick = {},
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ fun NavGraphBuilder.sendDestination(
|
||||
route = SEND_ROUTE,
|
||||
) {
|
||||
SendScreen(
|
||||
onNavigateAddSend = onNavigateToAddSend,
|
||||
onNavigateToAddSend = onNavigateToAddSend,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,8 @@ import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.ClipboardManager
|
||||
import androidx.compose.ui.platform.LocalClipboardManager
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.res.stringResource
|
||||
@@ -27,6 +29,7 @@ import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import com.x8bit.bitwarden.R
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.EventsEffect
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.IntentHandler
|
||||
import com.x8bit.bitwarden.ui.platform.base.util.toAnnotatedString
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenErrorContent
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenLoadingContent
|
||||
import com.x8bit.bitwarden.ui.platform.components.BitwardenMediumTopAppBar
|
||||
@@ -34,6 +37,7 @@ 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 com.x8bit.bitwarden.ui.tools.feature.send.handlers.SendHandlers
|
||||
import kotlinx.collections.immutable.persistentListOf
|
||||
|
||||
/**
|
||||
@@ -43,15 +47,22 @@ import kotlinx.collections.immutable.persistentListOf
|
||||
@OptIn(ExperimentalMaterial3Api::class)
|
||||
@Composable
|
||||
fun SendScreen(
|
||||
onNavigateAddSend: () -> Unit,
|
||||
onNavigateToAddSend: () -> Unit,
|
||||
viewModel: SendViewModel = hiltViewModel(),
|
||||
clipboardManager: ClipboardManager = LocalClipboardManager.current,
|
||||
intentHandler: IntentHandler = IntentHandler(context = LocalContext.current),
|
||||
) {
|
||||
val state by viewModel.stateFlow.collectAsStateWithLifecycle()
|
||||
val context = LocalContext.current
|
||||
EventsEffect(viewModel = viewModel) { event ->
|
||||
when (event) {
|
||||
is SendEvent.NavigateNewSend -> onNavigateAddSend()
|
||||
is SendEvent.CopyToClipboard -> {
|
||||
clipboardManager.setText(
|
||||
event.message(context.resources).toString().toAnnotatedString(),
|
||||
)
|
||||
}
|
||||
|
||||
is SendEvent.NavigateNewSend -> onNavigateToAddSend()
|
||||
|
||||
is SendEvent.NavigateToAboutSend -> {
|
||||
intentHandler.launchUri("https://bitwarden.com/products/send".toUri())
|
||||
@@ -65,6 +76,7 @@ fun SendScreen(
|
||||
}
|
||||
}
|
||||
|
||||
val sendHandlers = remember(viewModel) { SendHandlers.create(viewModel) }
|
||||
val scrollBehavior = TopAppBarDefaults.exitUntilCollapsedScrollBehavior(
|
||||
state = rememberTopAppBarState(),
|
||||
)
|
||||
@@ -135,6 +147,7 @@ fun SendScreen(
|
||||
is SendState.ViewState.Content -> SendContent(
|
||||
modifier = modifier,
|
||||
state = viewState,
|
||||
sendHandlers = sendHandlers,
|
||||
)
|
||||
|
||||
SendState.ViewState.Empty -> SendEmpty(
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.x8bit.bitwarden.ui.tools.feature.send
|
||||
|
||||
import android.os.Parcelable
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.lifecycle.SavedStateHandle
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import com.x8bit.bitwarden.R
|
||||
@@ -26,6 +27,7 @@ private const val KEY_STATE = "state"
|
||||
/**
|
||||
* View model for the send screen.
|
||||
*/
|
||||
@Suppress("TooManyFunctions")
|
||||
@HiltViewModel
|
||||
class SendViewModel @Inject constructor(
|
||||
savedStateHandle: SavedStateHandle,
|
||||
@@ -53,6 +55,11 @@ class SendViewModel @Inject constructor(
|
||||
SendAction.RefreshClick -> handleRefreshClick()
|
||||
SendAction.SearchClick -> handleSearchClick()
|
||||
SendAction.SyncClick -> handleSyncClick()
|
||||
is SendAction.CopyClick -> handleCopyClick(action)
|
||||
SendAction.FileTypeClick -> handleFileTypeClick()
|
||||
is SendAction.SendClick -> handleSendClick(action)
|
||||
is SendAction.ShareClick -> handleShareClick(action)
|
||||
SendAction.TextTypeClick -> handleTextTypeClick()
|
||||
is SendAction.Internal -> handleInternalAction(action)
|
||||
}
|
||||
|
||||
@@ -130,6 +137,31 @@ class SendViewModel @Inject constructor(
|
||||
// TODO: Add loading dialog state BIT-481
|
||||
vaultRepo.sync()
|
||||
}
|
||||
|
||||
private fun handleCopyClick(action: SendAction.CopyClick) {
|
||||
// TODO: Create a link and copy it to the clipboard BIT-??
|
||||
sendEvent(SendEvent.ShowToast("Not yet implemented".asText()))
|
||||
}
|
||||
|
||||
private fun handleSendClick(action: SendAction.SendClick) {
|
||||
// TODO: Navigate to the edit send screen BIT-??
|
||||
sendEvent(SendEvent.ShowToast("Not yet implemented".asText()))
|
||||
}
|
||||
|
||||
private fun handleShareClick(action: SendAction.ShareClick) {
|
||||
// TODO: Create a link and use the share sheet BIT-??
|
||||
sendEvent(SendEvent.ShowToast("Not yet implemented".asText()))
|
||||
}
|
||||
|
||||
private fun handleFileTypeClick() {
|
||||
// TODO: Navigate to the file type send list screen BIT-??
|
||||
sendEvent(SendEvent.ShowToast("Not yet implemented".asText()))
|
||||
}
|
||||
|
||||
private fun handleTextTypeClick() {
|
||||
// TODO: Navigate to the text type send list screen BIT-??
|
||||
sendEvent(SendEvent.ShowToast("Not yet implemented".asText()))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -150,12 +182,34 @@ data class SendState(
|
||||
abstract val shouldDisplayFab: Boolean
|
||||
|
||||
/**
|
||||
* Show the empty state.
|
||||
* Show the populated state.
|
||||
*/
|
||||
@Parcelize
|
||||
// TODO: Add actual content BIT-481
|
||||
data object Content : ViewState() {
|
||||
data class Content(
|
||||
val textTypeCount: Int,
|
||||
val fileTypeCount: Int,
|
||||
val sendItems: List<SendItem>,
|
||||
) : ViewState() {
|
||||
override val shouldDisplayFab: Boolean get() = true
|
||||
|
||||
/**
|
||||
* Represents the an individual send item to be displayed.
|
||||
*/
|
||||
@Parcelize
|
||||
data class SendItem(
|
||||
val id: String,
|
||||
val name: String,
|
||||
val deletionDate: String,
|
||||
val type: Type,
|
||||
) : Parcelable {
|
||||
/**
|
||||
* Indicates the type of send this, a text or file.
|
||||
*/
|
||||
enum class Type(@DrawableRes val iconRes: Int) {
|
||||
FILE(iconRes = R.drawable.ic_send_file),
|
||||
TEXT(iconRes = R.drawable.ic_send_text),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -220,6 +274,37 @@ sealed class SendAction {
|
||||
*/
|
||||
data object SyncClick : SendAction()
|
||||
|
||||
/**
|
||||
* User clicked the file type button.
|
||||
*/
|
||||
data object FileTypeClick : SendAction()
|
||||
|
||||
/**
|
||||
* User clicked the text type button.
|
||||
*/
|
||||
data object TextTypeClick : SendAction()
|
||||
|
||||
/**
|
||||
* User clicked the item row.
|
||||
*/
|
||||
data class SendClick(
|
||||
val sendItem: SendState.ViewState.Content.SendItem,
|
||||
) : SendAction()
|
||||
|
||||
/**
|
||||
* User clicked the copy item button.
|
||||
*/
|
||||
data class CopyClick(
|
||||
val sendItem: SendState.ViewState.Content.SendItem,
|
||||
) : SendAction()
|
||||
|
||||
/**
|
||||
* User clicked the share item button.
|
||||
*/
|
||||
data class ShareClick(
|
||||
val sendItem: SendState.ViewState.Content.SendItem,
|
||||
) : SendAction()
|
||||
|
||||
/**
|
||||
* Models actions that the [SendViewModel] itself will send.
|
||||
*/
|
||||
@@ -237,6 +322,11 @@ sealed class SendAction {
|
||||
* Models events for the send screen.
|
||||
*/
|
||||
sealed class SendEvent {
|
||||
/**
|
||||
* Copies the given [message] to the clipboard.
|
||||
*/
|
||||
data class CopyToClipboard(val message: Text) : SendEvent()
|
||||
|
||||
/**
|
||||
* Navigate to the new send screen.
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.x8bit.bitwarden.ui.tools.feature.send.handlers
|
||||
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.SendAction
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.SendState
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.SendViewModel
|
||||
|
||||
/**
|
||||
* A collection of handler functions for managing actions within the context of viewing
|
||||
* send items.
|
||||
*/
|
||||
data class SendHandlers(
|
||||
val onTextTypeClick: () -> Unit,
|
||||
val onFileTypeClick: () -> Unit,
|
||||
val onSendClick: (SendState.ViewState.Content.SendItem) -> Unit,
|
||||
val onEditSendClick: (SendState.ViewState.Content.SendItem) -> Unit,
|
||||
val onCopySendClick: (SendState.ViewState.Content.SendItem) -> Unit,
|
||||
val onShareSendClick: (SendState.ViewState.Content.SendItem) -> Unit,
|
||||
) {
|
||||
companion object {
|
||||
/**
|
||||
* Creates an instance of [SendHandlers] by binding actions to the provided [SendViewModel].
|
||||
*/
|
||||
fun create(
|
||||
viewModel: SendViewModel,
|
||||
): SendHandlers =
|
||||
SendHandlers(
|
||||
onTextTypeClick = { viewModel.trySendAction(SendAction.TextTypeClick) },
|
||||
onFileTypeClick = { viewModel.trySendAction(SendAction.FileTypeClick) },
|
||||
onSendClick = { viewModel.trySendAction(SendAction.SendClick(it)) },
|
||||
onEditSendClick = { viewModel.trySendAction(SendAction.SendClick(it)) },
|
||||
onCopySendClick = { viewModel.trySendAction(SendAction.CopyClick(it)) },
|
||||
onShareSendClick = { viewModel.trySendAction(SendAction.ShareClick(it)) },
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,13 @@
|
||||
package com.x8bit.bitwarden.ui.tools.feature.send.util
|
||||
|
||||
import com.bitwarden.core.SendType
|
||||
import com.bitwarden.core.SendView
|
||||
import com.x8bit.bitwarden.data.vault.repository.model.SendData
|
||||
import com.x8bit.bitwarden.ui.tools.feature.generator.util.toFormattedPattern
|
||||
import com.x8bit.bitwarden.ui.tools.feature.send.SendState
|
||||
|
||||
private const val DELETION_DATE_PATTERN: String = "MMM d, uuuu, hh:mm a"
|
||||
|
||||
/**
|
||||
* Transforms [SendData] into [SendState.ViewState].
|
||||
*/
|
||||
@@ -15,6 +19,19 @@ fun SendData.toViewState(): SendState.ViewState =
|
||||
?: SendState.ViewState.Empty
|
||||
|
||||
private fun List<SendView>.toSendContent(): SendState.ViewState.Content {
|
||||
// TODO: Populate with real data BIT-481
|
||||
return SendState.ViewState.Content
|
||||
return SendState.ViewState.Content(
|
||||
textTypeCount = this.count { it.type == SendType.TEXT },
|
||||
fileTypeCount = this.count { it.type == SendType.FILE },
|
||||
sendItems = this.map {
|
||||
SendState.ViewState.Content.SendItem(
|
||||
id = requireNotNull(it.id),
|
||||
name = it.name,
|
||||
deletionDate = it.deletionDate.toFormattedPattern(DELETION_DATE_PATTERN),
|
||||
type = when (it.type) {
|
||||
SendType.TEXT -> SendState.ViewState.Content.SendItem.Type.TEXT
|
||||
SendType.FILE -> SendState.ViewState.Content.SendItem.Type.FILE
|
||||
},
|
||||
)
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user