aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHarsh Shandilya <me@msfjarvis.dev>2022-10-09 18:02:49 +0530
committerHarsh Shandilya <me@msfjarvis.dev>2022-10-09 18:11:04 +0530
commitc866bb9fb195eb77b62221212a2b2f158ae7ae0e (patch)
tree99a1b4dc5ac27c9725656f09979831425ccb95e6
parent6d73b63435a2760ec9026090ecfea4846157b6ab (diff)
feat(app): support toggling read-only status in DecryptScreen
-rw-r--r--app/src/main/java/app/passwordstore/ui/crypto/DecryptScreen.kt56
-rw-r--r--ui-compose/src/main/kotlin/app/passwordstore/ui/compose/PasswordField.kt3
2 files changed, 54 insertions, 5 deletions
diff --git a/app/src/main/java/app/passwordstore/ui/crypto/DecryptScreen.kt b/app/src/main/java/app/passwordstore/ui/crypto/DecryptScreen.kt
index d48e70a7..64257709 100644
--- a/app/src/main/java/app/passwordstore/ui/crypto/DecryptScreen.kt
+++ b/app/src/main/java/app/passwordstore/ui/crypto/DecryptScreen.kt
@@ -19,6 +19,8 @@ import androidx.compose.ui.platform.LocalClipboardManager
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.AnnotatedString
+import androidx.compose.ui.text.capitalize
+import androidx.compose.ui.text.intl.Locale
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import app.passwordstore.R
@@ -32,11 +34,23 @@ import kotlin.time.ExperimentalTime
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
+/**
+ * Composable to show a [PasswordEntry]. It can be used for both read-only usage (decrypt screen) or
+ * read-write (encrypt screen) to allow sharing UI logic for both these screens and deferring all
+ * the cryptographic aspects to its parent.
+ *
+ * When [readOnly] is `true`, the Composable assumes that we're showcasing the provided [entry] to
+ * the user and does not offer any edit capabilities.
+ *
+ * When [readOnly] is `false`, the [TextField]s are rendered editable but currently do not pass up
+ * their "updated" state to anything. This will be changed in later commits.
+ */
@OptIn(ExperimentalTime::class, ExperimentalMaterial3Api::class)
@Composable
fun PasswordEntryScreen(
entryName: String,
entry: PasswordEntry,
+ readOnly: Boolean,
modifier: Modifier = Modifier,
) {
Scaffold(
@@ -61,21 +75,22 @@ fun PasswordEntryScreen(
value = entry.password!!,
label = "Password",
initialVisibility = false,
+ readOnly = readOnly,
modifier = Modifier.padding(bottom = 8.dp),
)
}
- if (entry.hasTotp()) {
+ if (entry.hasTotp() && readOnly) {
val totp by entry.totp.collectAsState(runBlocking { entry.totp.first() })
TextField(
value = totp.value,
onValueChange = {},
- readOnly = true,
+ readOnly = readOnly,
label = { Text("OTP (expires in ${totp.remainingTime.inWholeSeconds}s)") },
trailingIcon = { CopyButton({ totp.value }) },
modifier = Modifier.padding(bottom = 8.dp),
)
}
- if (entry.username != null) {
+ if (entry.username != null && readOnly) {
TextField(
value = entry.username!!,
onValueChange = {},
@@ -85,12 +100,42 @@ fun PasswordEntryScreen(
modifier = Modifier.padding(bottom = 8.dp),
)
}
+ ExtraContent(entry = entry, readOnly = readOnly)
}
}
}
}
@Composable
+@OptIn(ExperimentalMaterial3Api::class)
+private fun ExtraContent(
+ entry: PasswordEntry,
+ readOnly: Boolean,
+ modifier: Modifier = Modifier,
+) {
+ if (readOnly) {
+ entry.extraContent.forEach { (label, value) ->
+ TextField(
+ value = value,
+ onValueChange = {},
+ readOnly = true,
+ label = { Text(label.capitalize(Locale.current)) },
+ trailingIcon = { CopyButton({ value }) },
+ modifier = modifier.padding(bottom = 8.dp),
+ )
+ }
+ } else {
+ TextField(
+ value = entry.extraContentWithoutAuthData,
+ onValueChange = {},
+ readOnly = false,
+ label = { Text("Extra content") },
+ modifier = modifier,
+ )
+ }
+}
+
+@Composable
private fun CopyButton(
textToCopy: () -> String,
modifier: Modifier = Modifier,
@@ -110,7 +155,9 @@ private fun CopyButton(
@Preview
@Composable
private fun PasswordEntryPreview() {
- APSThemePreview { PasswordEntryScreen("Test Entry", createTestEntry()) }
+ APSThemePreview {
+ PasswordEntryScreen(entryName = "Test Entry", entry = createTestEntry(), readOnly = true)
+ }
}
private fun createTestEntry() =
@@ -121,6 +168,7 @@ private fun createTestEntry() =
|My Password
|otpauth://totp/ACME%20Co:john@example.com?secret=HXDMVJECJJWSRB3HWIZR4IFUGFTMXBOZ&issuer=ACME%20Co&algorithm=SHA1&digits=6&period=30
|login: msfjarvis
+ |URL: example.com
"""
.trimMargin()
.encodeToByteArray()
diff --git a/ui-compose/src/main/kotlin/app/passwordstore/ui/compose/PasswordField.kt b/ui-compose/src/main/kotlin/app/passwordstore/ui/compose/PasswordField.kt
index 81255979..2bdf2de3 100644
--- a/ui-compose/src/main/kotlin/app/passwordstore/ui/compose/PasswordField.kt
+++ b/ui-compose/src/main/kotlin/app/passwordstore/ui/compose/PasswordField.kt
@@ -21,13 +21,14 @@ public fun PasswordField(
value: String,
label: String,
initialVisibility: Boolean,
+ readOnly: Boolean,
modifier: Modifier = Modifier,
) {
var visible by remember { mutableStateOf(initialVisibility) }
TextField(
value = value,
onValueChange = {},
- readOnly = true,
+ readOnly = readOnly,
label = { Text(label) },
visualTransformation =
if (visible) VisualTransformation.None else PasswordVisualTransformation(),