From 1d7bdd60f9ef290ae1a07fc4ee4efd8a5910773e Mon Sep 17 00:00:00 2001 From: tapframe <85391825+tapframe@users.noreply.github.com> Date: Wed, 27 May 2026 11:39:57 +0530 Subject: [PATCH] fix(authscreen): keyboard to dismiss while tapping outside fixes #1138 --- .../com/nuvio/app/features/auth/AuthScreen.kt | 50 +++++++++++++++++-- 1 file changed, 47 insertions(+), 3 deletions(-) diff --git a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/auth/AuthScreen.kt b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/auth/AuthScreen.kt index c6362e85..a2774cf9 100644 --- a/composeApp/src/commonMain/kotlin/com/nuvio/app/features/auth/AuthScreen.kt +++ b/composeApp/src/commonMain/kotlin/com/nuvio/app/features/auth/AuthScreen.kt @@ -7,6 +7,8 @@ import androidx.compose.animation.togetherWith import androidx.compose.foundation.Image import androidx.compose.foundation.background import androidx.compose.foundation.clickable +import androidx.compose.foundation.gestures.awaitEachGesture +import androidx.compose.foundation.gestures.awaitFirstDown import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -40,13 +42,21 @@ import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.setValue import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.geometry.Rect import androidx.compose.ui.graphics.Color +import androidx.compose.ui.input.pointer.PointerEventPass +import androidx.compose.ui.input.pointer.pointerInput +import androidx.compose.ui.layout.LayoutCoordinates import androidx.compose.ui.layout.ContentScale +import androidx.compose.ui.layout.onGloballyPositioned +import androidx.compose.ui.layout.positionInRoot +import androidx.compose.ui.platform.LocalFocusManager import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType @@ -85,18 +95,34 @@ fun AuthScreen( ) { val authError by AuthRepository.error.collectAsStateWithLifecycle() val scope = rememberCoroutineScope() + val focusManager = LocalFocusManager.current var isSignUp by rememberSaveable { mutableStateOf(false) } var email by rememberSaveable { mutableStateOf("") } var password by rememberSaveable { mutableStateOf("") } var passwordVisible by rememberSaveable { mutableStateOf(false) } var isLoading by rememberSaveable { mutableStateOf(false) } + var emailFieldBounds by remember { mutableStateOf(null) } + var passwordFieldBounds by remember { mutableStateOf(null) } val statusBarTop = WindowInsets.statusBars.asPaddingValues().calculateTopPadding() Box( modifier = modifier .fillMaxSize() - .background(Color.Black), + .background(Color.Black) + .pointerInput(emailFieldBounds, passwordFieldBounds) { + awaitEachGesture { + val down = awaitFirstDown( + requireUnconsumed = false, + pass = PointerEventPass.Initial, + ) + val tappedTextField = listOfNotNull(emailFieldBounds, passwordFieldBounds) + .any { bounds -> bounds.contains(down.position) } + if (!tappedTextField) { + focusManager.clearFocus(force = true) + } + } + }, ) { Box( modifier = Modifier @@ -162,7 +188,11 @@ fun AuthScreen( email = it AuthRepository.clearError() }, - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .fillMaxWidth() + .onGloballyPositioned { coordinates -> + emailFieldBounds = coordinates.boundsInRoot() + }, singleLine = true, placeholder = { Text( @@ -195,7 +225,11 @@ fun AuthScreen( password = it AuthRepository.clearError() }, - modifier = Modifier.fillMaxWidth(), + modifier = Modifier + .fillMaxWidth() + .onGloballyPositioned { coordinates -> + passwordFieldBounds = coordinates.boundsInRoot() + }, singleLine = true, placeholder = { Text( @@ -386,3 +420,13 @@ fun AuthScreen( } } } + +private fun LayoutCoordinates.boundsInRoot(): Rect { + val position = positionInRoot() + return Rect( + left = position.x, + top = position.y, + right = position.x + size.width, + bottom = position.y + size.height, + ) +}