White text boxes — matches ios!144
An input is the one surface a person types into and reads back character by character, and a dark field on a dark ground gave it the least contrast on the screen at the moment it mattered most. Typed text reads 18.3:1 on white; the placeholder 4.6:1, because a placeholder is still text. ⚠️ **Its own colour, not `SurfaceAlt`.** That fill is shared with incoming bubbles and the tab pill, which stay dark — a white message bubble on this ground would read as somebody else's app. 🔴 **Every colour a field draws has to be named, not just the container.** Material derives label, placeholder, cursor and outline from the colour scheme, which is the DARK scheme here: setting only `containerColor` leaves a light-on-dark placeholder on a white box, and it simply disappears. iOS had the same failure in a different dialect — SwiftUI drew the placeholder and caret for a dark background until the field was given `.environment(\.colorScheme, .light)`. Two frameworks, one mistake: a white island in a dark app has to be told it is an island. One `fieldColors()` in `Theme.kt`, applied to all 34 `OutlinedTextField` call sites. Mechanical and wide rather than a new wrapper composable, because a wrapper would have to be adopted one screen at a time and the ones that were missed would be exactly the ones nobody looks at. ⚠️ The message composer is a `BasicTextField` and stays dark. It is a pill in the chat, not a form field, and turning it white would put a white bar across the bottom of every conversation. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
b824e626e7
commit
8fa66cd603
@@ -447,6 +447,7 @@ fun ColumnScope.GroupsSection(
|
|||||||
|
|
||||||
if (creating) {
|
if (creating) {
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = name,
|
value = name,
|
||||||
onValueChange = { name = it },
|
onValueChange = { name = it },
|
||||||
label = { Text("Group name") },
|
label = { Text("Group name") },
|
||||||
@@ -795,6 +796,7 @@ fun ColumnScope.AccountScreen(
|
|||||||
// same duplication the contact rows had.
|
// same duplication the contact rows had.
|
||||||
SettingsRow(label = "Display name") {}
|
SettingsRow(label = "Display name") {}
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = displayName,
|
value = displayName,
|
||||||
onValueChange = { displayName = it },
|
onValueChange = { displayName = it },
|
||||||
placeholder = { Text("How others see you", fontSize = 14.sp) },
|
placeholder = { Text("How others see you", fontSize = 14.sp) },
|
||||||
@@ -816,6 +818,7 @@ fun ColumnScope.AccountScreen(
|
|||||||
description = "Changing it signs this device out — that is what changing it means.",
|
description = "Changing it signs this device out — that is what changing it means.",
|
||||||
) {}
|
) {}
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = password,
|
value = password,
|
||||||
onValueChange = { password = it },
|
onValueChange = { password = it },
|
||||||
placeholder = { Text("At least 8 characters", fontSize = 14.sp) },
|
placeholder = { Text("At least 8 characters", fontSize = 14.sp) },
|
||||||
@@ -2923,6 +2926,7 @@ private fun ColumnScope.GroupMembers(
|
|||||||
|
|
||||||
if (renaming) {
|
if (renaming) {
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = draftName,
|
value = draftName,
|
||||||
onValueChange = { draftName = it },
|
onValueChange = { draftName = it },
|
||||||
label = { Text("Group name") },
|
label = { Text("Group name") },
|
||||||
@@ -3165,6 +3169,7 @@ fun ColumnScope.AddContactForm(
|
|||||||
fontSize = 12.sp, color = Palette.SecondaryText)
|
fontSize = 12.sp, color = Palette.SecondaryText)
|
||||||
Spacer(Modifier.height(Space.xs))
|
Spacer(Modifier.height(Space.xs))
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = gatePin, onValueChange = { gatePin = it; gateWrong = false },
|
value = gatePin, onValueChange = { gatePin = it; gateWrong = false },
|
||||||
placeholder = { Text("Parent PIN", fontSize = 14.sp) },
|
placeholder = { Text("Parent PIN", fontSize = 14.sp) },
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
@@ -3200,6 +3205,7 @@ fun ColumnScope.AddContactForm(
|
|||||||
val card = remember(username) { ContactCard.decode(username) }
|
val card = remember(username) { ContactCard.decode(username) }
|
||||||
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = username,
|
value = username,
|
||||||
onValueChange = {
|
onValueChange = {
|
||||||
username = it
|
username = it
|
||||||
@@ -3828,6 +3834,7 @@ fun ColumnScope.MailboxesSection(
|
|||||||
}
|
}
|
||||||
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = host,
|
value = host,
|
||||||
onValueChange = { host = it },
|
onValueChange = { host = it },
|
||||||
placeholder = { Text("relay.example.com", fontSize = 14.sp) },
|
placeholder = { Text("relay.example.com", fontSize = 14.sp) },
|
||||||
@@ -3836,6 +3843,7 @@ fun ColumnScope.MailboxesSection(
|
|||||||
)
|
)
|
||||||
Spacer(Modifier.height(Space.xs))
|
Spacer(Modifier.height(Space.xs))
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = passphrase,
|
value = passphrase,
|
||||||
onValueChange = { passphrase = it },
|
onValueChange = { passphrase = it },
|
||||||
placeholder = { Text("Your passphrase", fontSize = 14.sp) },
|
placeholder = { Text("Your passphrase", fontSize = 14.sp) },
|
||||||
@@ -4031,6 +4039,7 @@ private fun EditMessageSheet(
|
|||||||
text = {
|
text = {
|
||||||
Column {
|
Column {
|
||||||
androidx.compose.material3.OutlinedTextField(
|
androidx.compose.material3.OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = text,
|
value = text,
|
||||||
onValueChange = { text = it },
|
onValueChange = { text = it },
|
||||||
modifier = Modifier.fillMaxWidth().testTag("edit-field"),
|
modifier = Modifier.fillMaxWidth().testTag("edit-field"),
|
||||||
@@ -4169,6 +4178,7 @@ internal fun ReportSheet(
|
|||||||
|
|
||||||
Spacer(Modifier.height(Space.sm))
|
Spacer(Modifier.height(Space.sm))
|
||||||
androidx.compose.material3.OutlinedTextField(
|
androidx.compose.material3.OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = note,
|
value = note,
|
||||||
onValueChange = { note = it },
|
onValueChange = { note = it },
|
||||||
label = { Text("Anything you want to add (optional)") },
|
label = { Text("Anything you want to add (optional)") },
|
||||||
|
|||||||
@@ -145,6 +145,7 @@ private fun ColumnScope.FilesSetUp(
|
|||||||
Spacer(Modifier.height(Space.md))
|
Spacer(Modifier.height(Space.md))
|
||||||
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = passphrase, onValueChange = { passphrase = it },
|
value = passphrase, onValueChange = { passphrase = it },
|
||||||
label = { Text("Your Flamenet passphrase") },
|
label = { Text("Your Flamenet passphrase") },
|
||||||
visualTransformation = PasswordVisualTransformation(),
|
visualTransformation = PasswordVisualTransformation(),
|
||||||
@@ -153,6 +154,7 @@ private fun ColumnScope.FilesSetUp(
|
|||||||
)
|
)
|
||||||
Spacer(Modifier.height(Space.sm))
|
Spacer(Modifier.height(Space.sm))
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = again, onValueChange = { again = it },
|
value = again, onValueChange = { again = it },
|
||||||
label = { Text("Type it again") },
|
label = { Text("Type it again") },
|
||||||
visualTransformation = PasswordVisualTransformation(),
|
visualTransformation = PasswordVisualTransformation(),
|
||||||
@@ -187,6 +189,7 @@ private fun ColumnScope.FilesUnlock(
|
|||||||
fontSize = 14.sp, color = Palette.SecondaryText)
|
fontSize = 14.sp, color = Palette.SecondaryText)
|
||||||
Spacer(Modifier.height(Space.md))
|
Spacer(Modifier.height(Space.md))
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = passphrase, onValueChange = { passphrase = it },
|
value = passphrase, onValueChange = { passphrase = it },
|
||||||
label = { Text("Passphrase") },
|
label = { Text("Passphrase") },
|
||||||
visualTransformation = PasswordVisualTransformation(),
|
visualTransformation = PasswordVisualTransformation(),
|
||||||
@@ -452,6 +455,7 @@ private fun ColumnScope.AddFileSheet(
|
|||||||
Text("Add a file", fontWeight = FontWeight.Medium, fontSize = 16.sp)
|
Text("Add a file", fontWeight = FontWeight.Medium, fontSize = 16.sp)
|
||||||
Spacer(Modifier.height(Space.sm))
|
Spacer(Modifier.height(Space.sm))
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = name, onValueChange = { name = it },
|
value = name, onValueChange = { name = it },
|
||||||
label = { Text("Name") }, singleLine = true,
|
label = { Text("Name") }, singleLine = true,
|
||||||
modifier = Modifier.fillMaxWidth().testTag("files-add-name"),
|
modifier = Modifier.fillMaxWidth().testTag("files-add-name"),
|
||||||
@@ -510,6 +514,7 @@ private fun ColumnScope.FolderNameSheet(
|
|||||||
Text("New folder", fontWeight = FontWeight.Medium, fontSize = 16.sp)
|
Text("New folder", fontWeight = FontWeight.Medium, fontSize = 16.sp)
|
||||||
Spacer(Modifier.height(Space.sm))
|
Spacer(Modifier.height(Space.sm))
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = name, onValueChange = { name = it },
|
value = name, onValueChange = { name = it },
|
||||||
label = { Text("Name") }, singleLine = true,
|
label = { Text("Name") }, singleLine = true,
|
||||||
modifier = Modifier.fillMaxWidth().testTag("files-folder-name"),
|
modifier = Modifier.fillMaxWidth().testTag("files-folder-name"),
|
||||||
|
|||||||
@@ -187,6 +187,7 @@ private fun PassphraseDialog(
|
|||||||
Text(explainer, fontSize = 12.sp, color = Palette.SecondaryText)
|
Text(explainer, fontSize = 12.sp, color = Palette.SecondaryText)
|
||||||
Spacer(Modifier.height(Space.sm))
|
Spacer(Modifier.height(Space.sm))
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = phrase,
|
value = phrase,
|
||||||
onValueChange = { phrase = it },
|
onValueChange = { phrase = it },
|
||||||
placeholder = { Text("Passphrase", fontSize = 14.sp) },
|
placeholder = { Text("Passphrase", fontSize = 14.sp) },
|
||||||
@@ -197,6 +198,7 @@ private fun PassphraseDialog(
|
|||||||
if (requireRepeat) {
|
if (requireRepeat) {
|
||||||
Spacer(Modifier.height(Space.xs))
|
Spacer(Modifier.height(Space.xs))
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = repeat,
|
value = repeat,
|
||||||
onValueChange = { repeat = it },
|
onValueChange = { repeat = it },
|
||||||
placeholder = { Text("Repeat passphrase", fontSize = 14.sp) },
|
placeholder = { Text("Repeat passphrase", fontSize = 14.sp) },
|
||||||
|
|||||||
@@ -395,6 +395,7 @@ private fun ColumnScope.SignIn(model: MessengerViewModel, phase: MessengerViewMo
|
|||||||
Spacer(Modifier.height(Space.xl))
|
Spacer(Modifier.height(Space.xl))
|
||||||
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = relay,
|
value = relay,
|
||||||
onValueChange = model::setRelay,
|
onValueChange = model::setRelay,
|
||||||
label = { Text("Server") },
|
label = { Text("Server") },
|
||||||
@@ -415,6 +416,7 @@ private fun ColumnScope.SignIn(model: MessengerViewModel, phase: MessengerViewMo
|
|||||||
}
|
}
|
||||||
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = handle,
|
value = handle,
|
||||||
onValueChange = { handle = it },
|
onValueChange = { handle = it },
|
||||||
label = { Text("Handle") },
|
label = { Text("Handle") },
|
||||||
@@ -429,6 +431,7 @@ private fun ColumnScope.SignIn(model: MessengerViewModel, phase: MessengerViewMo
|
|||||||
// would be collecting something nobody needs.
|
// would be collecting something nobody needs.
|
||||||
if (needsEmail) {
|
if (needsEmail) {
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = email,
|
value = email,
|
||||||
onValueChange = { email = it },
|
onValueChange = { email = it },
|
||||||
label = { Text("Email") },
|
label = { Text("Email") },
|
||||||
@@ -444,6 +447,7 @@ private fun ColumnScope.SignIn(model: MessengerViewModel, phase: MessengerViewMo
|
|||||||
}
|
}
|
||||||
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = passphrase,
|
value = passphrase,
|
||||||
onValueChange = { passphrase = it },
|
onValueChange = { passphrase = it },
|
||||||
label = { Text("Passphrase") },
|
label = { Text("Passphrase") },
|
||||||
@@ -459,6 +463,7 @@ private fun ColumnScope.SignIn(model: MessengerViewModel, phase: MessengerViewMo
|
|||||||
// this device to refuse an under-13 sign-up, then forgotten. Nothing
|
// this device to refuse an under-13 sign-up, then forgotten. Nothing
|
||||||
// about age is sent to any server.
|
// about age is sent to any server.
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = birthYear,
|
value = birthYear,
|
||||||
onValueChange = { birthYear = it.filter(Char::isDigit).take(4) },
|
onValueChange = { birthYear = it.filter(Char::isDigit).take(4) },
|
||||||
label = { Text("Year of birth") },
|
label = { Text("Year of birth") },
|
||||||
@@ -569,6 +574,7 @@ private fun ColumnScope.ResetPassword(model: MessengerViewModel, handle: String)
|
|||||||
) { Text("Send a code") }
|
) { Text("Send a code") }
|
||||||
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = code,
|
value = code,
|
||||||
onValueChange = { code = it },
|
onValueChange = { code = it },
|
||||||
label = { Text("Code from the email") },
|
label = { Text("Code from the email") },
|
||||||
@@ -576,6 +582,7 @@ private fun ColumnScope.ResetPassword(model: MessengerViewModel, handle: String)
|
|||||||
modifier = Modifier.fillMaxWidth().testTag("reset-code"),
|
modifier = Modifier.fillMaxWidth().testTag("reset-code"),
|
||||||
)
|
)
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = fresh,
|
value = fresh,
|
||||||
onValueChange = { fresh = it },
|
onValueChange = { fresh = it },
|
||||||
label = { Text("New password") },
|
label = { Text("New password") },
|
||||||
|
|||||||
@@ -124,6 +124,7 @@ fun ColumnScope.MessagesScreen(
|
|||||||
Spacer(Modifier.height(Space.sm))
|
Spacer(Modifier.height(Space.sm))
|
||||||
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = query.value,
|
value = query.value,
|
||||||
onValueChange = { query.value = it },
|
onValueChange = { query.value = it },
|
||||||
placeholder = { Text("Search conversations") },
|
placeholder = { Text("Search conversations") },
|
||||||
|
|||||||
@@ -148,6 +148,7 @@ fun ColumnScope.NetworkSection(
|
|||||||
Spacer(Modifier.height(Space.md))
|
Spacer(Modifier.height(Space.md))
|
||||||
|
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = draft,
|
value = draft,
|
||||||
onValueChange = { draft = it },
|
onValueChange = { draft = it },
|
||||||
placeholder = { Text("obfs4 198.51.100.7:4444 …", fontSize = 13.sp) },
|
placeholder = { Text("obfs4 198.51.100.7:4444 …", fontSize = 13.sp) },
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ fun ParentalControlsSection() {
|
|||||||
)
|
)
|
||||||
Spacer(Modifier.height(Space.sm))
|
Spacer(Modifier.height(Space.sm))
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = newPin, onValueChange = { newPin = it },
|
value = newPin, onValueChange = { newPin = it },
|
||||||
placeholder = { Text("Parent PIN (at least 4 digits)", fontSize = 14.sp) },
|
placeholder = { Text("Parent PIN (at least 4 digits)", fontSize = 14.sp) },
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
@@ -64,6 +65,7 @@ fun ParentalControlsSection() {
|
|||||||
)
|
)
|
||||||
Spacer(Modifier.height(Space.xs))
|
Spacer(Modifier.height(Space.xs))
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = repeatPin, onValueChange = { repeatPin = it },
|
value = repeatPin, onValueChange = { repeatPin = it },
|
||||||
placeholder = { Text("Repeat PIN", fontSize = 14.sp) },
|
placeholder = { Text("Repeat PIN", fontSize = 14.sp) },
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
@@ -86,6 +88,7 @@ fun ParentalControlsSection() {
|
|||||||
fontSize = 12.sp, color = Palette.SecondaryText)
|
fontSize = 12.sp, color = Palette.SecondaryText)
|
||||||
Spacer(Modifier.height(Space.sm))
|
Spacer(Modifier.height(Space.sm))
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = pinEntry, onValueChange = { pinEntry = it; wrong = false },
|
value = pinEntry, onValueChange = { pinEntry = it; wrong = false },
|
||||||
placeholder = { Text("Parent PIN", fontSize = 14.sp) },
|
placeholder = { Text("Parent PIN", fontSize = 14.sp) },
|
||||||
singleLine = true,
|
singleLine = true,
|
||||||
|
|||||||
@@ -357,6 +357,7 @@ private fun StoryActions(
|
|||||||
+ "saw this story can read it.", fontSize = 13.sp)
|
+ "saw this story can read it.", fontSize = 13.sp)
|
||||||
Spacer(Modifier.height(Space.sm))
|
Spacer(Modifier.height(Space.sm))
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = draft, onValueChange = { draft = it },
|
value = draft, onValueChange = { draft = it },
|
||||||
placeholder = { Text("Message") },
|
placeholder = { Text("Message") },
|
||||||
modifier = Modifier.fillMaxWidth().testTag("story-reply-field"),
|
modifier = Modifier.fillMaxWidth().testTag("story-reply-field"),
|
||||||
@@ -453,6 +454,7 @@ fun StoryComposerDialog(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
androidx.compose.material3.OutlinedTextField(
|
androidx.compose.material3.OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = caption.value,
|
value = caption.value,
|
||||||
onValueChange = { caption.value = it },
|
onValueChange = { caption.value = it },
|
||||||
placeholder = { Text("Add a caption…") },
|
placeholder = { Text("Add a caption…") },
|
||||||
@@ -464,6 +466,7 @@ fun StoryComposerDialog(
|
|||||||
// §6.13 — attach a live stream. The picked picture becomes its
|
// §6.13 — attach a live stream. The picked picture becomes its
|
||||||
// poster: what people see before deciding whether to connect.
|
// poster: what people see before deciding whether to connect.
|
||||||
androidx.compose.material3.OutlinedTextField(
|
androidx.compose.material3.OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = streamUrl.value,
|
value = streamUrl.value,
|
||||||
onValueChange = { streamUrl.value = it },
|
onValueChange = { streamUrl.value = it },
|
||||||
label = { Text("Live stream link (optional)", fontSize = 12.sp) },
|
label = { Text("Live stream link (optional)", fontSize = 12.sp) },
|
||||||
@@ -706,6 +709,7 @@ private fun TextStoryComposer(onDismiss: () -> Unit, onPost: (String) -> Unit) {
|
|||||||
title = { Text("New story") },
|
title = { Text("New story") },
|
||||||
text = {
|
text = {
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = text,
|
value = text,
|
||||||
onValueChange = { text = it },
|
onValueChange = { text = it },
|
||||||
placeholder = { Text("Say something") },
|
placeholder = { Text("Say something") },
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.draw.clip
|
import androidx.compose.ui.draw.clip
|
||||||
import androidx.compose.ui.draw.shadow
|
import androidx.compose.ui.draw.shadow
|
||||||
import androidx.compose.ui.graphics.Brush
|
import androidx.compose.ui.graphics.Brush
|
||||||
|
import androidx.compose.material3.OutlinedTextFieldDefaults
|
||||||
import androidx.compose.ui.graphics.Color
|
import androidx.compose.ui.graphics.Color
|
||||||
import androidx.compose.ui.text.font.FontWeight
|
import androidx.compose.ui.text.font.FontWeight
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
@@ -154,6 +155,50 @@ fun groundBrush(): Brush =
|
|||||||
fun accentBrush(): Brush =
|
fun accentBrush(): Brush =
|
||||||
Brush.verticalGradient(listOf(Palette.GradientTop, Palette.GradientBottom))
|
Brush.verticalGradient(listOf(Palette.GradientTop, Palette.GradientBottom))
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Text fields, and only text fields.
|
||||||
|
*
|
||||||
|
* 🔴 **White, on a dark app, deliberately.** An input is the one surface a
|
||||||
|
* person types into and reads back character by character, and a dark field on
|
||||||
|
* a dark ground gives it the least contrast on the screen at the moment it
|
||||||
|
* matters most. Typed text reads 18.3:1 on white; the placeholder 4.6:1,
|
||||||
|
* because a placeholder is still text. Matches `Theme.fieldFill` on iOS.
|
||||||
|
*
|
||||||
|
* ⚠️ **Not `SurfaceAlt`.** That fill is shared with incoming bubbles and the
|
||||||
|
* tab pill, which stay dark — a white message bubble on this ground would read
|
||||||
|
* as somebody else's app.
|
||||||
|
*
|
||||||
|
* ⚠️ Every colour a field draws has to be named, not just the container.
|
||||||
|
* Material derives label, placeholder, cursor and outline from the colour
|
||||||
|
* scheme, which is the DARK scheme here — leaving any of them unset puts a
|
||||||
|
* light-on-dark colour on a white box, and the placeholder simply disappears.
|
||||||
|
*/
|
||||||
|
object FieldPalette {
|
||||||
|
val fill = Color(0xFFFFFFFF)
|
||||||
|
val ink = Color(0xFF0E1230)
|
||||||
|
val hint = Color(0xFF6B7590)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun fieldColors() = OutlinedTextFieldDefaults.colors(
|
||||||
|
focusedContainerColor = FieldPalette.fill,
|
||||||
|
unfocusedContainerColor = FieldPalette.fill,
|
||||||
|
disabledContainerColor = FieldPalette.fill,
|
||||||
|
errorContainerColor = FieldPalette.fill,
|
||||||
|
focusedTextColor = FieldPalette.ink,
|
||||||
|
unfocusedTextColor = FieldPalette.ink,
|
||||||
|
disabledTextColor = FieldPalette.hint,
|
||||||
|
errorTextColor = FieldPalette.ink,
|
||||||
|
focusedLabelColor = FieldPalette.hint,
|
||||||
|
unfocusedLabelColor = FieldPalette.hint,
|
||||||
|
disabledLabelColor = FieldPalette.hint,
|
||||||
|
focusedPlaceholderColor = FieldPalette.hint,
|
||||||
|
unfocusedPlaceholderColor = FieldPalette.hint,
|
||||||
|
cursorColor = Palette.Accent,
|
||||||
|
focusedBorderColor = Palette.Accent,
|
||||||
|
unfocusedBorderColor = FieldPalette.hint,
|
||||||
|
)
|
||||||
|
|
||||||
/** Corner radii, matching `Theme.Radius` on iOS. */
|
/** Corner radii, matching `Theme.Radius` on iOS. */
|
||||||
object Radius {
|
object Radius {
|
||||||
val small = 10.dp
|
val small = 10.dp
|
||||||
|
|||||||
@@ -129,6 +129,7 @@ private fun ColumnScope.NoWallet(model: MessengerViewModel) {
|
|||||||
Text("Already have one?", fontWeight = FontWeight.Medium, fontSize = 16.sp)
|
Text("Already have one?", fontWeight = FontWeight.Medium, fontSize = 16.sp)
|
||||||
Spacer(Modifier.height(Space.xs))
|
Spacer(Modifier.height(Space.xs))
|
||||||
OutlinedTextField(
|
OutlinedTextField(
|
||||||
|
colors = fieldColors(),
|
||||||
value = phrase,
|
value = phrase,
|
||||||
onValueChange = { phrase = it },
|
onValueChange = { phrase = it },
|
||||||
placeholder = { Text("Your 12 or 24 word recovery phrase", fontSize = 13.sp) },
|
placeholder = { Text("Your 12 or 24 word recovery phrase", fontSize = 13.sp) },
|
||||||
|
|||||||
Reference in New Issue
Block a user