@@ -2,13 +2,9 @@ package app.passwordstore.ui.crypto
2
2
3
3
import androidx.compose.foundation.layout.Box
4
4
import androidx.compose.foundation.layout.Column
5
- import androidx.compose.foundation.layout.IntrinsicSize
6
5
import androidx.compose.foundation.layout.fillMaxSize
7
6
import androidx.compose.foundation.layout.fillMaxWidth
8
7
import androidx.compose.foundation.layout.padding
9
- import androidx.compose.foundation.layout.width
10
- import androidx.compose.material3.Icon
11
- import androidx.compose.material3.IconButton
12
8
import androidx.compose.material3.MaterialTheme
13
9
import androidx.compose.material3.Scaffold
14
10
import androidx.compose.material3.Text
@@ -17,40 +13,28 @@ import androidx.compose.runtime.Composable
17
13
import androidx.compose.runtime.collectAsState
18
14
import androidx.compose.runtime.getValue
19
15
import androidx.compose.ui.Modifier
20
- import androidx.compose.ui.platform.LocalClipboardManager
21
16
import androidx.compose.ui.res.painterResource
22
17
import androidx.compose.ui.res.stringResource
23
- import androidx.compose.ui.text.AnnotatedString
24
18
import androidx.compose.ui.text.capitalize
25
19
import androidx.compose.ui.text.intl.Locale
26
20
import androidx.compose.ui.tooling.preview.Preview
27
21
import androidx.compose.ui.unit.dp
28
22
import app.passwordstore.R
29
23
import app.passwordstore.data.passfile.PasswordEntry
30
24
import app.passwordstore.ui.APSAppBar
25
+ import app.passwordstore.ui.compose.CopyButton
31
26
import app.passwordstore.ui.compose.PasswordField
32
27
import app.passwordstore.ui.compose.theme.APSThemePreview
33
28
import app.passwordstore.util.time.UserClock
34
29
import app.passwordstore.util.totp.UriTotpFinder
35
30
import kotlinx.coroutines.flow.first
36
31
import kotlinx.coroutines.runBlocking
37
32
38
- /* *
39
- * Composable to show a [PasswordEntry]. It can be used for both read-only usage (decrypt screen) or
40
- * read-write (encrypt screen) to allow sharing UI logic for both these screens and deferring all
41
- * the cryptographic aspects to its parent.
42
- *
43
- * When [readOnly] is `true`, the Composable assumes that we're showcasing the provided [entry] to
44
- * the user and does not offer any edit capabilities.
45
- *
46
- * When [readOnly] is `false`, the [TextField]s are rendered editable but currently do not pass up
47
- * their "updated" state to anything. This will be changed in later commits.
48
- */
33
+ /* * Composable to show a decrypted [PasswordEntry]. */
49
34
@Composable
50
- fun PasswordEntryScreen (
35
+ fun ViewPasswordScreen (
51
36
entryName : String ,
52
37
entry : PasswordEntry ,
53
- readOnly : Boolean ,
54
38
onNavigateUp : () -> Unit ,
55
39
modifier : Modifier = Modifier ,
56
40
) {
@@ -71,32 +55,32 @@ fun PasswordEntryScreen(
71
55
value = entry.password!! ,
72
56
label = stringResource(R .string.password),
73
57
initialVisibility = false ,
74
- readOnly = readOnly ,
58
+ readOnly = true ,
75
59
modifier = Modifier .padding(bottom = 8 .dp).fillMaxWidth(),
76
60
)
77
61
}
78
- if (entry.hasTotp() && readOnly ) {
62
+ if (entry.hasTotp()) {
79
63
val totp by entry.totp.collectAsState(runBlocking { entry.totp.first() })
80
64
TextField (
81
65
value = totp.value,
82
66
onValueChange = {},
83
67
readOnly = true ,
84
68
label = { Text (" OTP (expires in ${totp.remainingTime.inWholeSeconds} s)" ) },
85
- trailingIcon = { CopyButton ({ totp.value } ) },
69
+ trailingIcon = { CopyButton (totp.value, R .string.copy_label ) },
86
70
modifier = Modifier .padding(bottom = 8 .dp).fillMaxWidth(),
87
71
)
88
72
}
89
- if (entry.username != null && readOnly ) {
73
+ if (entry.username != null ) {
90
74
TextField (
91
75
value = entry.username!! ,
92
76
onValueChange = {},
93
77
readOnly = true ,
94
78
label = { Text (stringResource(R .string.username)) },
95
- trailingIcon = { CopyButton ({ entry.username!! } ) },
79
+ trailingIcon = { CopyButton (entry.username!! , R .string.copy_label ) },
96
80
modifier = Modifier .padding(bottom = 8 .dp).fillMaxWidth(),
97
81
)
98
82
}
99
- ExtraContent (entry = entry, readOnly = readOnly )
83
+ ExtraContent (entry = entry)
100
84
}
101
85
}
102
86
}
@@ -105,56 +89,27 @@ fun PasswordEntryScreen(
105
89
@Composable
106
90
private fun ExtraContent (
107
91
entry : PasswordEntry ,
108
- readOnly : Boolean ,
109
92
modifier : Modifier = Modifier ,
110
93
) {
111
- if (readOnly) {
112
- entry.extraContent.forEach { (label, value) ->
113
- TextField (
114
- value = value,
115
- onValueChange = {},
116
- readOnly = true ,
117
- label = { Text (label.capitalize(Locale .current)) },
118
- trailingIcon = { CopyButton ({ value }) },
119
- modifier = modifier.padding(bottom = 8 .dp).fillMaxWidth(),
120
- )
121
- }
122
- } else {
94
+ entry.extraContent.forEach { (label, value) ->
123
95
TextField (
124
- value = entry.extraContentString ,
96
+ value = value ,
125
97
onValueChange = {},
126
- readOnly = false ,
127
- label = { Text (" Extra content" ) },
128
- modifier = modifier.fillMaxWidth(),
129
- )
130
- }
131
- }
132
-
133
- @Composable
134
- private fun CopyButton (
135
- textToCopy : () -> String ,
136
- modifier : Modifier = Modifier ,
137
- ) {
138
- val clipboard = LocalClipboardManager .current
139
- IconButton (
140
- onClick = { clipboard.setText(AnnotatedString (textToCopy())) },
141
- modifier = modifier,
142
- ) {
143
- Icon (
144
- painter = painterResource(R .drawable.ic_content_copy),
145
- contentDescription = stringResource(R .string.copy_password),
98
+ readOnly = true ,
99
+ label = { Text (label.capitalize(Locale .current)) },
100
+ trailingIcon = { CopyButton (value, R .string.copy_label) },
101
+ modifier = modifier.padding(bottom = 8 .dp).fillMaxWidth(),
146
102
)
147
103
}
148
104
}
149
105
150
106
@Preview
151
107
@Composable
152
- private fun PasswordEntryPreview () {
108
+ private fun ViewPasswordScreenPreview () {
153
109
APSThemePreview {
154
- PasswordEntryScreen (
110
+ ViewPasswordScreen (
155
111
entryName = " Test Entry" ,
156
112
entry = createTestEntry(),
157
- readOnly = true ,
158
113
onNavigateUp = {},
159
114
)
160
115
}
0 commit comments