1package com.peachpasswords.ui.vault23import androidx.compose.foundation.background4import androidx.compose.foundation.clickable5import androidx.compose.foundation.interaction.MutableInteractionSource6import androidx.compose.foundation.interaction.collectIsPressedAsState7import androidx.compose.foundation.layout.Arrangement8import androidx.compose.foundation.layout.Box9import androidx.compose.foundation.layout.Column10import androidx.compose.foundation.layout.Row11import androidx.compose.foundation.layout.Spacer12import androidx.compose.foundation.layout.fillMaxWidth13import androidx.compose.foundation.layout.height14import androidx.compose.foundation.layout.heightIn15import androidx.compose.foundation.layout.navigationBarsPadding16import androidx.compose.foundation.layout.padding17import androidx.compose.material3.ExperimentalMaterial3Api18import androidx.compose.material3.ModalBottomSheet19import androidx.compose.material3.Text20import androidx.compose.material3.rememberModalBottomSheetState21import androidx.compose.runtime.Composable22import androidx.compose.runtime.getValue23import androidx.compose.runtime.remember24import androidx.compose.ui.Alignment25import androidx.compose.ui.Modifier26import androidx.compose.ui.draw.drawBehind27import androidx.compose.ui.geometry.Offset28import androidx.compose.ui.geometry.Size29import androidx.compose.ui.graphics.Color30import androidx.compose.ui.text.font.FontStyle31import androidx.compose.ui.text.style.TextAlign32import androidx.compose.ui.unit.dp33import androidx.compose.ui.unit.sp34import com.peachpasswords.ui.theme.LocalPeachAccent35import com.peachpasswords.ui.theme.peachColors36import com.peachpasswords.ui.theme.PeachType37import com.peachpasswords.vault.VaultEntry38import com.peachpasswords.vault.hasTOTP39404142434445464748@OptIn(ExperimentalMaterial3Api::class)49@Composable50fun ContextMenuSheet(51 entry: VaultEntry,52 onCopyPassword: () -> Unit,53 onCopyUsername: () -> Unit,54 onCopyTotp: () -> Unit,55 onEdit: () -> Unit,56 onMoveToTrash: () -> Unit,57 onDismiss: () -> Unit,58) {59 val sheetState = rememberModalBottomSheetState(skipPartiallyExpanded = true)6061 ModalBottomSheet(62 onDismissRequest = onDismiss,63 sheetState = sheetState,64 containerColor = peachColors.SurfaceElevated,65 dragHandle = null,66 ) {67 Column(68 Modifier69 .fillMaxWidth()70 .padding(top = 8.dp)71 .navigationBarsPadding(),72 ) {73 74 Text(75 text = entry.title,76 color = peachColors.T0,77 style = PeachType.entryNameList.copy(fontSize = 15.sp),78 modifier = Modifier.padding(horizontal = 20.dp, vertical = 12.dp),79 )80 Divider()8182 val username = entry.username ?: entry.email83 if (!entry.password.isNullOrEmpty()) {84 ActionRow(label = "Copy password", onClick = { onCopyPassword(); onDismiss() })85 }86 if (!username.isNullOrEmpty()) {87 ActionRow(label = "Copy username", onClick = { onCopyUsername(); onDismiss() })88 }89 if (entry.hasTOTP()) {90 ActionRow(label = "Copy TOTP code", onClick = { onCopyTotp(); onDismiss() })91 }92 ActionRow(label = "Edit", onClick = { onEdit(); onDismiss() })93 ActionRow(94 label = "Move to trash",95 textColor = peachColors.Breach,96 onClick = { onMoveToTrash(); onDismiss() },97 )9899 Divider()100 CancelRow(onClick = onDismiss)101 Spacer(Modifier.height(4.dp))102 }103 }104}105106@Composable107private fun Divider() {108 Box(109 Modifier110 .fillMaxWidth()111 .height(1.dp)112 .background(peachColors.T3),113 )114}115116117118119120@Composable121private fun ActionRow(122 label: String,123 textColor: Color = peachColors.T0,124 onClick: () -> Unit,125) {126 val accent = LocalPeachAccent.current127 val interaction = remember { MutableInteractionSource() }128 val pressed by interaction.collectIsPressedAsState()129 Row(130 modifier = Modifier131 .fillMaxWidth()132 .heightIn(min = 44.dp)133 .clickable(interactionSource = interaction, indication = null, onClick = onClick)134 .background(if (pressed) peachColors.T4 else Color.Transparent)135 .drawBehind {136 if (pressed) {137 drawRect(138 color = accent,139 topLeft = Offset.Zero,140 size = Size(2.dp.toPx(), size.height),141 )142 }143 }144 .padding(horizontal = 20.dp, vertical = 12.dp),145 verticalAlignment = Alignment.CenterVertically,146 ) {147 Text(148 text = label,149 color = textColor,150 style = PeachType.bodyMono.copy(fontSize = 12.sp),151 )152 }153}154155@Composable156private fun CancelRow(onClick: () -> Unit) {157 Row(158 modifier = Modifier159 .fillMaxWidth()160 .heightIn(min = 44.dp)161 .clickable(onClick = onClick)162 .padding(horizontal = 20.dp, vertical = 12.dp),163 horizontalArrangement = Arrangement.Center,164 verticalAlignment = Alignment.CenterVertically,165 ) {166 Text(167 text = "Cancel",168 color = peachColors.T2,169 style = PeachType.labelMono.copy(fontSize = 11.sp),170 textAlign = TextAlign.Center,171 )172 }173}