Skip to content

Commit 6a9af1c

Browse files
committed
[Feature] [Item] Add domain chip menu for editing and deletion
1 parent 8b86898 commit 6a9af1c

3 files changed

Lines changed: 91 additions & 6 deletions

File tree

feature/item/create/src/main/kotlin/de/davis/keygo/feature/item/create/presentation/password/PasswordContent.kt

Lines changed: 85 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,25 +2,37 @@ package de.davis.keygo.feature.item.create.presentation.password
22

33
import android.content.res.Configuration
44
import androidx.compose.foundation.layout.Arrangement
5+
import androidx.compose.foundation.layout.Box
56
import androidx.compose.foundation.layout.Column
67
import androidx.compose.foundation.layout.consumeWindowInsets
78
import androidx.compose.foundation.layout.fillMaxSize
89
import androidx.compose.foundation.layout.fillMaxWidth
910
import androidx.compose.foundation.layout.imePadding
1011
import androidx.compose.foundation.layout.padding
12+
import androidx.compose.foundation.layout.size
13+
import androidx.compose.foundation.layout.widthIn
14+
import androidx.compose.foundation.layout.wrapContentSize
1115
import androidx.compose.foundation.text.KeyboardOptions
1216
import androidx.compose.foundation.text.input.rememberTextFieldState
17+
import androidx.compose.foundation.text.input.setTextAndPlaceCursorAtEnd
1318
import androidx.compose.material.icons.Icons
1419
import androidx.compose.material.icons.automirrored.filled.ArrowBack
1520
import androidx.compose.material.icons.filled.AutoAwesome
21+
import androidx.compose.material.icons.filled.Delete
1622
import androidx.compose.material.icons.filled.Done
23+
import androidx.compose.material.icons.filled.Edit
1724
import androidx.compose.material.icons.filled.QrCodeScanner
25+
import androidx.compose.material3.DropdownMenuGroup
26+
import androidx.compose.material3.DropdownMenuItem
27+
import androidx.compose.material3.DropdownMenuPopup
1828
import androidx.compose.material3.ExperimentalMaterial3Api
1929
import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
2030
import androidx.compose.material3.Icon
2131
import androidx.compose.material3.IconButton
2232
import androidx.compose.material3.InputChip
33+
import androidx.compose.material3.MaterialTheme
2334
import androidx.compose.material3.MediumFlexibleTopAppBar
35+
import androidx.compose.material3.MenuDefaults
2436
import androidx.compose.material3.Scaffold
2537
import androidx.compose.material3.Text
2638
import androidx.compose.material3.TopAppBarDefaults
@@ -29,6 +41,7 @@ import androidx.compose.runtime.getValue
2941
import androidx.compose.runtime.mutableStateOf
3042
import androidx.compose.runtime.saveable.rememberSaveable
3143
import androidx.compose.runtime.setValue
44+
import androidx.compose.ui.Alignment
3245
import androidx.compose.ui.Modifier
3346
import androidx.compose.ui.focus.onFocusChanged
3447
import androidx.compose.ui.input.nestedscroll.nestedScroll
@@ -216,10 +229,19 @@ internal fun PasswordContent(state: PasswordUiState, onEvent: (PasswordUiEvent)
216229
Text(text = detectedScheme ?: "https://")
217230
}
218231
) { item, selected ->
219-
InputChip(
220-
selected = selected,
221-
onClick = { /* TODO: maybe allow editing? but definitely removing */ },
222-
label = { Text(text = item.value) }
232+
MenuChip(
233+
chipText = item.value,
234+
chipSelected = selected,
235+
onDeleteClick = {
236+
onEvent(PasswordUiEvent.OnDeleteDomain(item.value))
237+
},
238+
onModifyClick = {
239+
// TODO:
240+
// 1. when the user does not submit the new domain, rollback to the old domaine
241+
// 2. when the user clears the text-field and the focus is lost, rollback to old domain
242+
onEvent(PasswordUiEvent.OnDeleteDomain(item.value))
243+
domainTextFieldState.setTextAndPlaceCursorAtEnd(item.value)
244+
}
223245
)
224246
}
225247
}
@@ -289,6 +311,64 @@ internal fun PasswordContent(state: PasswordUiState, onEvent: (PasswordUiEvent)
289311
}
290312
}
291313

314+
315+
@OptIn(ExperimentalMaterial3ExpressiveApi::class)
316+
@Composable
317+
private fun MenuChip(
318+
chipText: String,
319+
chipSelected: Boolean,
320+
onDeleteClick: () -> Unit,
321+
onModifyClick: () -> Unit
322+
) {
323+
var expanded by rememberSaveable { mutableStateOf(false) }
324+
325+
Box(
326+
modifier = Modifier.wrapContentSize(Alignment.TopStart)
327+
) {
328+
InputChip(
329+
selected = chipSelected,
330+
onClick = { expanded = !expanded },
331+
label = { Text(text = chipText) }
332+
)
333+
334+
DropdownMenuPopup(
335+
expanded = expanded,
336+
onDismissRequest = { expanded = false },
337+
modifier = Modifier.widthIn(min = 175.dp)
338+
) {
339+
DropdownMenuGroup(
340+
shapes = MenuDefaults.groupShape(0, 1),
341+
containerColor = MaterialTheme.colorScheme.surfaceContainerHigh,
342+
) {
343+
DropdownMenuItem(
344+
onClick = onModifyClick,
345+
text = { Text(text = stringResource(R.string.edit)) },
346+
leadingIcon = {
347+
Icon(
348+
imageVector = Icons.Default.Edit,
349+
modifier = Modifier.size(MenuDefaults.LeadingIconSize),
350+
contentDescription = null
351+
)
352+
},
353+
shape = MenuDefaults.itemShape(0, 2).shape,
354+
)
355+
DropdownMenuItem(
356+
onClick = onDeleteClick,
357+
text = { Text(text = stringResource(R.string.delete)) },
358+
leadingIcon = {
359+
Icon(
360+
imageVector = Icons.Default.Delete,
361+
modifier = Modifier.size(MenuDefaults.LeadingIconSize),
362+
contentDescription = null
363+
)
364+
},
365+
shape = MenuDefaults.itemShape(1, 2).shape,
366+
)
367+
}
368+
}
369+
}
370+
}
371+
292372
private val DELIMITERS = setOf(',', ' ')
293373

294374
@Preview
@@ -311,4 +391,4 @@ private fun PasswordContentPreview() {
311391
onEvent = {}
312392
)
313393
}
314-
}
394+
}

feature/item/create/src/main/kotlin/de/davis/keygo/feature/item/create/presentation/password/model/PasswordUiState.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
package de.davis.keygo.feature.item.create.presentation.password.model
22

33
import androidx.compose.foundation.text.input.TextFieldState
4+
import androidx.compose.runtime.Immutable
45
import de.davis.keygo.core.item.domain.model.DomainInfo
56
import de.davis.keygo.core.item.domain.model.Password
67
import de.davis.keygo.feature.item.core.presentation.model.InputFieldError
78

9+
@Immutable
810
internal data class PasswordUiState(
911
val nameTextFieldState: TextFieldState = TextFieldState(),
1012
val notesTextFieldState: TextFieldState = TextFieldState(),

feature/item/create/src/main/res/values/strings.xml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,10 @@
5757
<string name="generate_password_content_description">Generate Password</string>
5858

5959
<string name="add_domains">Add domains</string>
60-
60+
6161
<string name="database_error">An unexpected database error has occurred: %s</string>
6262
<string name="invalid_vault_id">Vault item ID can not be found</string>
63+
64+
<string name="delete">Delete</string>
65+
<string name="edit">Edit</string>
6366
</resources>

0 commit comments

Comments
 (0)