fix(ime): gate draft-saving editor back handlers behind KeyboardAwareBackHandler

Follow-up to the chat composer fix. The native post/editor screens install
the same pattern that stranded the IME insets: a BackHandler that saves a
draft and pops the screen. When the keyboard is up and the user leaves with a
predictive back gesture, the pop races (and cancels) the IME close animation,
leaving WindowInsets.ime — every imePadding() in the app — stuck at the
keyboard height on release builds.

Route these through KeyboardAwareBackHandler so the system dismisses the
keyboard first (clean animation) and the screen only pops once it is down:

- ShortNotePostScreen
- LongFormPostScreen
- NewProductScreen
- GenericCommentPostScreen
- NewGoalScreen
- NewWorkoutScreen
- NewPublicMessageScreen
- AwardBadgeScreen

Left as plain BackHandler: handlers with no text field (VoiceReplyScreen), and
handlers whose back does something other than pop a text-entry screen — WebView
history (WebAppScreen, NostrAppScreen), in-browser navigation (GitCodeTab,
GitCommitLog), drawer close (AccountSwitcherAndLeftDrawerLayout), and call/PiP
(CallScreen, NestActivityContent) — where deferring to keyboard dismissal would
change back semantics.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012dT2RLbPZzan2hULL2cmc6
This commit is contained in:
Claude
2026-07-28 17:49:34 +00:00
parent eeefacca9e
commit c3fccc7153
8 changed files with 16 additions and 16 deletions
@@ -20,7 +20,6 @@
*/
package com.vitorpamplona.amethyst.ui.note.nip22Comments
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.clickable
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Box
@@ -67,6 +66,7 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
import com.vitorpamplona.amethyst.ui.actions.uploads.TakePictureButton
import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideoButton
import com.vitorpamplona.amethyst.ui.navigation.bottombars.KeyboardAwareBackHandler
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
import com.vitorpamplona.amethyst.ui.navigation.topbars.PostingTopBar
import com.vitorpamplona.amethyst.ui.note.BaseUserPicture
@@ -177,7 +177,7 @@ fun GenericCommentPostScreen(
StrippingFailureDialog(postViewModel.strippingFailureConfirmation)
BackHandler {
KeyboardAwareBackHandler {
accountViewModel.launchSigner {
postViewModel.sendDraftSync()
postViewModel.cancel()
@@ -20,7 +20,6 @@
*/
package com.vitorpamplona.amethyst.ui.screen.loggedIn.badges.award
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@@ -52,6 +51,7 @@ import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.ui.components.Nip05OrPubkeyLine
import com.vitorpamplona.amethyst.model.User
import com.vitorpamplona.amethyst.ui.navigation.bottombars.KeyboardAwareBackHandler
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.navigation.topbars.SavingTopBar
import com.vitorpamplona.amethyst.ui.note.UserPicture
@@ -88,7 +88,7 @@ fun AwardBadgeScreen(
onDispose { userSuggestions.reset() }
}
BackHandler {
KeyboardAwareBackHandler {
nav.popBack()
}
@@ -20,7 +20,6 @@
*/
package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip23LongForm
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
@@ -96,6 +95,7 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideoButton
import com.vitorpamplona.amethyst.ui.components.MyAsyncImage
import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField
import com.vitorpamplona.amethyst.ui.components.markdown.RenderContentAsMarkdown
import com.vitorpamplona.amethyst.ui.navigation.bottombars.KeyboardAwareBackHandler
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
import com.vitorpamplona.amethyst.ui.navigation.topbars.PostingTopBar
import com.vitorpamplona.amethyst.ui.note.creators.contentWarning.ContentSensitivityExplainer
@@ -149,7 +149,7 @@ fun LongFormPostScreen(
StrippingFailureDialog(postViewModel.strippingFailureConfirmation)
BackHandler {
KeyboardAwareBackHandler {
accountViewModel.launchSigner {
postViewModel.sendDraftSync()
postViewModel.cancel()
@@ -20,7 +20,6 @@
*/
package com.vitorpamplona.amethyst.ui.screen.loggedIn.discover.nip99Classifieds
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
@@ -53,6 +52,7 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
import com.vitorpamplona.amethyst.ui.actions.uploads.SelectedMedia
import com.vitorpamplona.amethyst.ui.actions.uploads.TakePictureButton
import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideoButton
import com.vitorpamplona.amethyst.ui.navigation.bottombars.KeyboardAwareBackHandler
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
import com.vitorpamplona.amethyst.ui.navigation.topbars.PostingTopBar
@@ -141,7 +141,7 @@ fun NewProductScreen(
StrippingFailureDialog(postViewModel.strippingFailureConfirmation)
BackHandler {
KeyboardAwareBackHandler {
accountViewModel.launchSigner {
postViewModel.sendDraftSync()
postViewModel.cancel()
@@ -23,7 +23,6 @@ package com.vitorpamplona.amethyst.ui.screen.loggedIn.home
import android.annotation.SuppressLint
import android.content.Intent
import android.net.Uri
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.clickable
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement
@@ -93,6 +92,7 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.VoiceMessagePreview
import com.vitorpamplona.amethyst.ui.components.OutlinedThinPaddingTextField
import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField
import com.vitorpamplona.amethyst.ui.components.getActivity
import com.vitorpamplona.amethyst.ui.navigation.bottombars.KeyboardAwareBackHandler
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
import com.vitorpamplona.amethyst.ui.navigation.topbars.PostingTopBar
@@ -235,7 +235,7 @@ internal fun NewPostScreenInner(
StrippingFailureDialog(postViewModel.strippingFailureConfirmation)
BackHandler {
KeyboardAwareBackHandler {
accountViewModel.launchSigner {
postViewModel.sendDraftSync()
postViewModel.cancel()
@@ -20,7 +20,6 @@
*/
package com.vitorpamplona.amethyst.ui.screen.loggedIn.home.nip75Goals
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
@@ -48,6 +47,7 @@ import androidx.compose.ui.text.input.KeyboardType
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel
import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.ui.navigation.bottombars.KeyboardAwareBackHandler
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
import com.vitorpamplona.amethyst.ui.navigation.topbars.PostingTopBar
@@ -81,7 +81,7 @@ fun NewGoalScreen(
accountViewModel: AccountViewModel,
nav: INav,
) {
BackHandler {
KeyboardAwareBackHandler {
goalViewModel.cancel()
nav.popBack()
}
@@ -20,7 +20,6 @@
*/
package com.vitorpamplona.amethyst.ui.screen.loggedIn.notifications.publicMessages
import androidx.activity.compose.BackHandler
import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement.Absolute.spacedBy
import androidx.compose.foundation.layout.Column
@@ -64,6 +63,7 @@ import com.vitorpamplona.amethyst.ui.actions.uploads.SelectFromGallery
import com.vitorpamplona.amethyst.ui.actions.uploads.TakePictureButton
import com.vitorpamplona.amethyst.ui.actions.uploads.TakeVideoButton
import com.vitorpamplona.amethyst.ui.components.ThinPaddingTextField
import com.vitorpamplona.amethyst.ui.navigation.bottombars.KeyboardAwareBackHandler
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.navigation.navs.Nav
import com.vitorpamplona.amethyst.ui.navigation.topbars.PostingTopBar
@@ -134,7 +134,7 @@ fun NewPublicMessageScreen(
StrippingFailureDialog(postViewModel.strippingFailureConfirmation)
BackHandler {
KeyboardAwareBackHandler {
accountViewModel.launchSigner {
postViewModel.sendDraftSync()
postViewModel.cancel()
@@ -20,7 +20,6 @@
*/
package com.vitorpamplona.amethyst.ui.screen.loggedIn.workouts
import androidx.activity.compose.BackHandler
import androidx.compose.animation.Crossfade
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
@@ -61,6 +60,7 @@ import com.vitorpamplona.amethyst.R
import com.vitorpamplona.amethyst.commons.icons.symbols.Icon
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbol
import com.vitorpamplona.amethyst.commons.icons.symbols.MaterialSymbols
import com.vitorpamplona.amethyst.ui.navigation.bottombars.KeyboardAwareBackHandler
import com.vitorpamplona.amethyst.ui.navigation.navs.INav
import com.vitorpamplona.amethyst.ui.navigation.routes.Route
import com.vitorpamplona.amethyst.ui.navigation.topbars.PostingTopBar
@@ -80,7 +80,7 @@ fun NewWorkoutScreen(
postViewModel.init(accountViewModel)
postViewModel.prefill(prefill)
BackHandler {
KeyboardAwareBackHandler {
postViewModel.cancel()
nav.popBack()
}