diff --git a/app/src/main/kotlin/ir/thatsmejavad/backgroundable/common/ui/ClearFocusOnKeyboardDismissModifier.kt b/app/src/main/kotlin/ir/thatsmejavad/backgroundable/common/ui/ClearFocusOnKeyboardDismissModifier.kt new file mode 100644 index 0000000..78d2170 --- /dev/null +++ b/app/src/main/kotlin/ir/thatsmejavad/backgroundable/common/ui/ClearFocusOnKeyboardDismissModifier.kt @@ -0,0 +1,66 @@ +package ir.thatsmejavad.backgroundable.common.ui + +import android.graphics.Rect +import android.view.View +import android.view.ViewTreeObserver +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.State +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.produceState +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue +import androidx.compose.ui.Modifier +import androidx.compose.ui.composed +import androidx.compose.ui.focus.onFocusEvent +import androidx.compose.ui.platform.LocalFocusManager +import androidx.compose.ui.platform.LocalView + +@Composable +fun Modifier.clearFocusOnKeyboardDismiss(): Modifier = composed { + var isFocused by remember { mutableStateOf(false) } + var keyboardAppearedSinceLastFocused by remember { mutableStateOf(false) } + + if (isFocused) { + val isKeyboardOpen by rememberIsKeyboardOpen() + + val focusManager = LocalFocusManager.current + LaunchedEffect(isKeyboardOpen) { + if (isKeyboardOpen) { + keyboardAppearedSinceLastFocused = true + } else if (keyboardAppearedSinceLastFocused) { + focusManager.clearFocus() + } + } + } + onFocusEvent { + if (isFocused != it.isFocused) { + isFocused = it.isFocused + if (isFocused) { + keyboardAppearedSinceLastFocused = false + } + } + } +} + +@Composable +fun rememberIsKeyboardOpen(): State { + val view = LocalView.current + + return produceState(initialValue = view.isKeyboardOpen()) { + val viewTreeObserver = view.viewTreeObserver + val listener = ViewTreeObserver.OnGlobalLayoutListener { value = view.isKeyboardOpen() } + viewTreeObserver.addOnGlobalLayoutListener(listener) + + awaitDispose { viewTreeObserver.removeOnGlobalLayoutListener(listener) } + } +} + +fun View.isKeyboardOpen(): Boolean { + val rect = Rect() + getWindowVisibleDisplayFrame(rect) + val screenHeight = rootView.height + val keypadHeight = screenHeight - rect.bottom + return keypadHeight > screenHeight * 0.15 +} diff --git a/app/src/main/kotlin/ir/thatsmejavad/backgroundable/screens/search/SearchScreen.kt b/app/src/main/kotlin/ir/thatsmejavad/backgroundable/screens/search/SearchScreen.kt index d8220e4..b8fdfa1 100644 --- a/app/src/main/kotlin/ir/thatsmejavad/backgroundable/screens/search/SearchScreen.kt +++ b/app/src/main/kotlin/ir/thatsmejavad/backgroundable/screens/search/SearchScreen.kt @@ -74,6 +74,7 @@ import ir.thatsmejavad.backgroundable.R import ir.thatsmejavad.backgroundable.common.ui.BackgroundableScaffold import ir.thatsmejavad.backgroundable.common.ui.MediaCard import ir.thatsmejavad.backgroundable.common.ui.ObserveSnackbars +import ir.thatsmejavad.backgroundable.common.ui.clearFocusOnKeyboardDismiss import ir.thatsmejavad.backgroundable.core.AppScreens import ir.thatsmejavad.backgroundable.core.Constants.NAVIGATION_BAR_HEIGHT import ir.thatsmejavad.backgroundable.core.getErrorMessage @@ -160,6 +161,7 @@ private fun SearchScreen( .statusBarsPadding() .padding(horizontal = padding) .fillMaxWidth() + .clearFocusOnKeyboardDismiss() .onFocusChanged { isFocused = it.isFocused }