From a870b17801c6e6ad6455632e6bff3b1082368e59 Mon Sep 17 00:00:00 2001 From: null Date: Tue, 16 Jun 2026 19:14:06 -0500 Subject: [PATCH] refactor: update AcceptInviteScreen with theme-consistent visuals and layout --- .../app/ui/pairing/AcceptInviteScreen.kt | 114 ++++++++++++++++-- 1 file changed, 103 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/com/couplesconnect/app/ui/pairing/AcceptInviteScreen.kt b/app/src/main/java/com/couplesconnect/app/ui/pairing/AcceptInviteScreen.kt index 8c55dbcc..f08bbaa1 100644 --- a/app/src/main/java/com/couplesconnect/app/ui/pairing/AcceptInviteScreen.kt +++ b/app/src/main/java/com/couplesconnect/app/ui/pairing/AcceptInviteScreen.kt @@ -1,6 +1,7 @@ package com.couplesconnect.app.ui.pairing import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Spacer @@ -12,6 +13,7 @@ import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawingPadding import androidx.compose.foundation.layout.size import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions import androidx.compose.foundation.verticalScroll @@ -19,12 +21,13 @@ import androidx.compose.material.icons.Icons import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.Button import androidx.compose.material3.ButtonDefaults +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults import androidx.compose.material3.CircularProgressIndicator import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.OutlinedTextField import androidx.compose.material3.Scaffold import androidx.compose.material3.SnackbarHost import androidx.compose.material3.SnackbarHostState @@ -40,10 +43,15 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color +import androidx.compose.ui.graphics.SolidColor import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.text.AnnotatedString +import androidx.compose.ui.text.input.OffsetMapping import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardCapitalization import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.input.TransformedText +import androidx.compose.ui.text.input.VisualTransformation import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import androidx.hilt.navigation.compose.hiltViewModel @@ -55,6 +63,7 @@ import com.couplesconnect.app.ui.settings.SettingsMuted import com.couplesconnect.app.ui.settings.SettingsOnPrimary import com.couplesconnect.app.ui.settings.SettingsPrimary import com.couplesconnect.app.ui.settings.SettingsPrimaryDeep +import com.couplesconnect.app.ui.settings.SettingsSoft @OptIn(ExperimentalMaterial3Api::class) @Composable @@ -119,22 +128,16 @@ fun AcceptInviteScreen( Spacer(Modifier.height(36.dp)) - OutlinedTextField( + InviteCodeEntryCard( value = state.code, onValueChange = viewModel::updateCode, - label = { Text("Invite code") }, - placeholder = { Text("ABC123") }, - singleLine = true, isError = state.error != null, - supportingText = state.error?.let { error -> { Text(error, color = SettingsDanger) } }, + error = state.error, modifier = Modifier.fillMaxWidth(), - textStyle = MaterialTheme.typography.headlineSmall.copy( - textAlign = TextAlign.Center, - letterSpacing = androidx.compose.ui.unit.TextUnit.Unspecified - ), keyboardOptions = KeyboardOptions( - keyboardType = KeyboardType.Text, + keyboardType = KeyboardType.Ascii, capitalization = KeyboardCapitalization.Characters, + autoCorrectEnabled = false, imeAction = ImeAction.Done ), keyboardActions = KeyboardActions(onDone = { focusManager.clearFocus(); viewModel.lookupCode() }) @@ -171,3 +174,92 @@ fun AcceptInviteScreen( } } } + +@Composable +private fun InviteCodeEntryCard( + value: String, + onValueChange: (String) -> Unit, + isError: Boolean, + error: String?, + modifier: Modifier = Modifier, + keyboardOptions: KeyboardOptions, + keyboardActions: KeyboardActions +) { + Column( + modifier = modifier, + horizontalAlignment = Alignment.CenterHorizontally + ) { + Card( + modifier = Modifier.fillMaxWidth(), + colors = CardDefaults.cardColors( + containerColor = SettingsSoft + ), + elevation = CardDefaults.cardElevation(defaultElevation = 0.dp) + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .padding(32.dp), + contentAlignment = Alignment.Center + ) { + BasicTextField( + value = value, + onValueChange = onValueChange, + modifier = Modifier.fillMaxWidth(), + singleLine = true, + textStyle = MaterialTheme.typography.displaySmall.copy( + color = if (isError) SettingsDanger else SettingsPrimaryDeep, + textAlign = TextAlign.Center + ), + cursorBrush = SolidColor(SettingsPrimaryDeep), + keyboardOptions = keyboardOptions, + keyboardActions = keyboardActions, + visualTransformation = InviteCodeVisualTransformation, + decorationBox = { innerTextField -> + if (value.isBlank()) { + Text( + text = "ABC – 123", + style = MaterialTheme.typography.displaySmall, + color = SettingsPrimaryDeep.copy(alpha = 0.36f), + textAlign = TextAlign.Center, + modifier = Modifier.fillMaxWidth() + ) + } + innerTextField() + } + ) + } + } + + if (error != null) { + Spacer(Modifier.height(8.dp)) + Text( + text = error, + style = MaterialTheme.typography.bodySmall, + color = SettingsDanger, + textAlign = TextAlign.Center + ) + } + } +} + +private object InviteCodeVisualTransformation : VisualTransformation { + override fun filter(text: AnnotatedString): TransformedText { + val raw = text.text + val transformed = raw.chunked(3).joinToString(" – ") + + val mapping = object : OffsetMapping { + override fun originalToTransformed(offset: Int): Int = + if (offset <= 3) offset else offset + 3 + + override fun transformedToOriginal(offset: Int): Int = + when { + offset <= 3 -> offset + offset <= 6 -> 3 + else -> offset - 3 + }.coerceIn(0, raw.length) + } + + return TransformedText(AnnotatedString(transformed), mapping) + } +}