diff --git a/app/src/main/kotlin/io/flamenet/messenger/app/MainActivity.kt b/app/src/main/kotlin/io/flamenet/messenger/app/MainActivity.kt index 6dbccb0..b347a78 100644 --- a/app/src/main/kotlin/io/flamenet/messenger/app/MainActivity.kt +++ b/app/src/main/kotlin/io/flamenet/messenger/app/MainActivity.kt @@ -13,6 +13,9 @@ import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.HorizontalDivider import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.background +import androidx.compose.ui.text.style.TextAlign +import androidx.compose.ui.graphics.Color +import androidx.compose.foundation.layout.width import androidx.compose.ui.semantics.semantics import androidx.compose.ui.semantics.contentDescription import androidx.compose.foundation.shape.CircleShape @@ -208,7 +211,43 @@ private fun ColumnScope.SignIn(model: MessengerViewModel, phase: MessengerViewMo // Only a relay keeping its own accounts needs an address for reset mail. val needsEmail = registering && site?.accountProvider == SiteConfig.AccountProvider.LOCAL - Text("Flamenet Messenger", style = MaterialTheme.typography.headlineMedium) + // 🔴 **The kit's Welcome screen, which is a masthead and not a form + // heading.** A logo mark, a 40pt greeting, and one line saying what this + // is — centred, with room above it. This was a 24pt product name jammed + // against a Server field, which is the layout of a login dialog rather + // than the first thing anyone sees of the app. See `DESIGN.md`. + // + // ⚠️ The kit's Welcome has no fields on it at all — it is a splash before + // a phone number is asked for. Flamenet does not ask for a phone number + // and has nothing to put on a second screen, so the masthead and the form + // share one. The typography and the centring are the kit's; the fields + // are ours. + Spacer(Modifier.height(Space.xl)) + Column( + modifier = Modifier.fillMaxWidth(), + horizontalAlignment = Alignment.CenterHorizontally, + ) { + Box( + modifier = Modifier + .size(48.dp) + .clip(RoundedCornerShape(Radius.medium)) + .background(MaterialTheme.colorScheme.primary), + contentAlignment = Alignment.Center, + ) { + Text("F", fontSize = 24.sp, fontWeight = FontWeight.Bold, color = Color.White) + } + Spacer(Modifier.height(Space.lg)) + Text("Hi there!", fontSize = 40.sp, fontWeight = FontWeight.Bold) + Spacer(Modifier.height(Space.sm)) + Text( + "Flamenet Messenger. End-to-end encrypted, no phone number, and it " + + "runs on whichever server you point it at.", + fontSize = 14.sp, + color = Palette.SecondaryText, + textAlign = TextAlign.Center, + ) + } + Spacer(Modifier.height(Space.xl)) OutlinedTextField( value = relay, @@ -274,18 +313,29 @@ private fun ColumnScope.SignIn(model: MessengerViewModel, phase: MessengerViewMo Text(it, color = MaterialTheme.colorScheme.error, modifier = Modifier.testTag("error")) } - Button( - onClick = { - model.signIn(handle.trim(), passphrase, register = registering, email = email.trim()) - }, - enabled = !phase.busy && handle.isNotBlank() && passphrase.isNotBlank() && - (!needsEmail || email.isNotBlank()), - modifier = Modifier.fillMaxWidth().testTag("submit"), - ) { - if (phase.busy) { - CircularProgressIndicator(modifier = Modifier.size(20.dp), strokeWidth = 2.dp) - } else { - Text(if (registering) "Create account" else "Sign in") + // ⚠️ 240 wide and centred, which is the kit's primary button on this + // screen — not a full-width slab. A button that spans the phone reads as + // the bottom of a form; one that does not reads as a choice. + Spacer(Modifier.height(Space.md)) + Box(modifier = Modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { + Button( + onClick = { + model.signIn(handle.trim(), passphrase, register = registering, email = email.trim()) + }, + enabled = !phase.busy && handle.isNotBlank() && passphrase.isNotBlank() && + (!needsEmail || email.isNotBlank()), + shape = RoundedCornerShape(KitButton.radius), + modifier = Modifier.width(240.dp).height(KitButton.height).testTag("submit"), + ) { + if (phase.busy) { + CircularProgressIndicator(modifier = Modifier.size(20.dp), strokeWidth = 2.dp) + } else { + Text( + if (registering) "Create account" else "Sign in", + fontSize = 14.sp, + fontWeight = FontWeight.Medium, + ) + } } } diff --git a/app/src/main/kotlin/io/flamenet/messenger/app/Theme.kt b/app/src/main/kotlin/io/flamenet/messenger/app/Theme.kt index 93ee3f1..8a96db5 100644 --- a/app/src/main/kotlin/io/flamenet/messenger/app/Theme.kt +++ b/app/src/main/kotlin/io/flamenet/messenger/app/Theme.kt @@ -21,11 +21,12 @@ import androidx.compose.ui.unit.sp /** * The Flamenet design system. * - * 🔴 **Taken from flamenetmessenger.com, not invented.** The site declares - * `--flame: #ff5a1f`, `--blue: #3b6fff`, `--accent: #2dd4a7` over a dark navy - * ground (`--bg: #0a0e1a`, `--panel: #121a2e`). The accents transfer as-is; - * the site's `--ink`/`--muted` are light-on-dark and are NOT pasted in here, - * because the apps are light. Dark mode does use the site's real grounds. + * 🔴 **Taken from the design kit, measured out of the Sketch file.** This + * comment used to say the palette came from flamenetmessenger.com and quoted + * `--flame: #ff5a1f` — which had already been retired from the public pages, + * so the app was carrying a brand colour the brand no longer used, on the + * authority of a comment nobody rechecked. The values here are read from the + * kit's own symbols; see `Palette`. * * 🔴 **One palette, two apps.** iOS carries the same values under the same * names in `Sources/Theme/Theme.swift`. This file's comment used to claim the @@ -39,32 +40,39 @@ import androidx.compose.ui.unit.sp * untouched — this is a skin over working screens. */ object Palette { - // Brand — the site's --flame. - // ⚠️ White on Ember is about 3.1:1: fine for a bold button label (AA - // Large), NOT fine for small text. Small text and links use EmberDeep. - val Ember = Color(0xFFFF5A1F) - val EmberDeep = Color(0xFFC4400F) - val EmberSoft = Color(0x1AFF5A1F) + // 🔴 **The design kit's palette, measured out of the file** — not sampled + // from a render and not approximated. The text colours below are the two + // that actually appear in its symbols: #090710 on 165 text layers and + // #505C69 on 164. The accent is the one it uses at 12pt as well as on + // buttons, so it is their link colour, not only their fill. + // + // ⚠️ These names used to say Ember, and held orange. The orange was the + // brand when this app was written and is not any more — the public pages + // carry none of it — so the names go with the colour rather than outliving + // it. A constant called `Ember` holding blue is how a palette drifts back. + val Accent = Color(0xFF2298FF) // buttons, bubbles, links + val AccentBright = Color(0xFF4FACFE) // the kit's lighter primary swatch + val AccentSoft = Color(0x1A2298FF) - // The site's other two accents, used sparingly. - val Blue = Color(0xFF3B6FFF) // --blue, informational only - val Teal = Color(0xFF2DD4A7) // --accent, success and presence + val Teal = Color(0xFF3BD5B2) // success and presence + val Pink = Color(0xFFED497C) // the kit's alert accent - // Neutrals: the site's navy family resolved for a LIGHT ground. - // ⚠️ --ink (#e8edf7) and --muted (#9aa7c2) are light-on-dark values and - // would be invisible here, so they are not pasted in literally. - val Ink = Color(0xFF0F1626) - val Mist = Color(0xFFF6F8FC) // the light ground (was 'Parchment' when the palette was warm) - val SurfaceAlt = Color(0xFFEDF1F8) - val IncomingBubble = Color(0xFFEDF1F8) - val AvatarFill = Color(0xFFE4EAF6) - val SecondaryText = Color(0xFF5A6884) - val Divider = Color(0x1A1F2B45) + // Neutrals, all from the kit. + val Ink = Color(0xFF090710) + val Mist = Color(0xFFF9F9F9) // the page ground + val SurfaceAlt = Color(0xFFF3F3F3) // received bubbles, pills, bands + val IncomingBubble = Color(0xFFF3F3F3) + // ⚠️ A blue-tinted grey rather than the flat #F3F3F3: an initials avatar + // needs to read as a circle against the surface behind it, and two greys a + // shade apart do not. + val AvatarFill = Color(0xFFE8F1FB) + val SecondaryText = Color(0xFF505C69) + val Divider = Color(0x1A505C69) // Semantic - val Success = Color(0xFF1F9E7A) + val Success = Color(0xFF3BD5B2) val Warning = Color(0xFFB8860B) - val Danger = Color(0xFFC0392B) + val Danger = Color(0xFFED497C) // Dark-mode grounds — these ARE the site's, since the site is dark. val InkSurface = Color(0xFF121A2E) // --panel @@ -187,9 +195,9 @@ fun MessengerTheme(content: @Composable () -> Unit) { MaterialTheme( colorScheme = if (dark) { darkColorScheme( - primary = Palette.Ember, + primary = Palette.AccentBright, onPrimary = Color.White, - secondary = Palette.EmberDeep, + secondary = Palette.Accent, background = Palette.NightGround, surface = Palette.InkSurface, surfaceVariant = Palette.InkSurface, @@ -201,9 +209,13 @@ fun MessengerTheme(content: @Composable () -> Unit) { ) } else { lightColorScheme( - primary = Palette.EmberDeep, + // ⚠️ The kit's #2298FF on white is about 3.3:1 — fine for a + // bold button label, not for small text. Anything small and + // blue must use a darker step; the two places that do are the + // section labels and the timestamps, and both are grey. + primary = Palette.Accent, onPrimary = Color.White, - secondary = Palette.Ember, + secondary = Palette.AccentBright, background = Palette.Mist, surface = Color.White, surfaceVariant = Palette.SurfaceAlt,