Skip to content

Commit

Permalink
[MBL-1942] Hotfix for keyboard covering input fields in Messages, Com…
Browse files Browse the repository at this point in the history
…ments, & Replies (#2191)

Update layout root padding based on IME insets in Messages, Comments,
and Thread screens.

Previously, when the device keyboard was opened it would cover the
messaging input field. Set the bottom padding of the layout's root view
based on IME insets to keep the input field visible.

This is the same logic as in `WindowInsetsUtil.manageEdgeToEdge()`
with a slight adjustment to handle the keyboard.

---------

Co-authored-by: Tony Teate <tonyteate@0d9c4fcdf1>
Co-authored-by: jlplks <[email protected]>
  • Loading branch information
3 people authored Dec 21, 2024
1 parent 802bba4 commit 13f486f
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,16 @@ package com.kickstarter.ui.activities
import android.content.Intent
import android.os.Bundle
import android.view.View
import android.view.ViewGroup
import androidx.activity.addCallback
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.recyclerview.widget.ConcatAdapter
import com.kickstarter.R
import com.kickstarter.databinding.ActivityCommentsLayoutBinding
Expand All @@ -30,7 +36,6 @@ import com.kickstarter.ui.extensions.finishWithAnimation
import com.kickstarter.ui.extensions.hideKeyboard
import com.kickstarter.ui.extensions.setUpConnectivityStatusCheck
import com.kickstarter.ui.views.OnCommentComposerViewClickedListener
import com.kickstarter.utils.WindowInsetsUtil
import com.kickstarter.viewmodels.CommentsViewModel.CommentsViewModel
import com.kickstarter.viewmodels.CommentsViewModel.Factory
import io.reactivex.disposables.CompositeDisposable
Expand All @@ -56,15 +61,28 @@ class CommentsActivity :

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)

binding = ActivityCommentsLayoutBinding.inflate(layoutInflater)
WindowInsetsUtil.manageEdgeToEdge(
window,
binding.root
)
val view: View = binding.root

setContentView(view)

ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
v.updateLayoutParams<ViewGroup.MarginLayoutParams> {
// Apply the left, right, top, and bottom margins based on the insets
leftMargin = insets.left
bottomMargin = insets.bottom
rightMargin = insets.right
topMargin = insets.top
}

val imeInsets = windowInsets.getInsets(WindowInsetsCompat.Type.ime())
v.updatePadding(bottom = imeInsets.bottom)

WindowInsetsCompat.CONSUMED
}

setUpConnectivityStatusCheck(lifecycle)

val env = this.getEnvironment()?.let { env ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,16 @@ import android.os.Bundle
import android.text.Html
import android.util.Pair
import android.view.View
import android.view.ViewGroup
import android.view.WindowManager
import androidx.activity.addCallback
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.core.widget.doOnTextChanged
import androidx.recyclerview.widget.LinearLayoutManager
import com.google.android.material.appbar.AppBarLayout
Expand All @@ -30,7 +36,6 @@ import com.kickstarter.ui.adapters.MessagesAdapter
import com.kickstarter.ui.extensions.finishWithAnimation
import com.kickstarter.ui.extensions.setUpConnectivityStatusCheck
import com.kickstarter.ui.extensions.startActivityWithTransition
import com.kickstarter.utils.WindowInsetsUtil
import com.kickstarter.viewmodels.MessagesViewModel
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
Expand All @@ -52,13 +57,39 @@ class MessagesActivity : AppCompatActivity() {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// Set the window to allow drawing under the system bars (status, nav bars),
// making them transparent, and enabling edge-to-edge display.
WindowCompat.setDecorFitsSystemWindows(window, false)

binding = MessagesLayoutBinding.inflate(layoutInflater)
WindowInsetsUtil.manageEdgeToEdge(
window,
binding.root
)
setContentView(binding.root)

// Listen for window insets (which represent system UI like status and navigation bars)
// and apply those insets to the view's layout parameters.
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, windowInsets ->
// Extract the insets that represent the system bars (status and navigation bars)
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())

// Update the view's layout margins with the insets so the content avoids overlapping
// with system bars. You can choose to apply top, left, bottom, and right insets as needed.
v.updateLayoutParams<ViewGroup.MarginLayoutParams> {
// Apply the left, right, top, and bottom margins based on the insets
leftMargin = insets.left
bottomMargin = insets.bottom
rightMargin = insets.right
topMargin = insets.top
}

val imeInsets = windowInsets.getInsets(WindowInsetsCompat.Type.ime())

v.updatePadding(bottom = imeInsets.bottom)

// Return CONSUMED to indicate that the window insets have been handled and
// should not be passed down to child views. If you want child views to handle insets,
// you can return the windowInsets instead.
WindowInsetsCompat.CONSUMED
}

setUpConnectivityStatusCheck(lifecycle)

val environment = this.getEnvironment()?.let { env ->
Expand Down
29 changes: 24 additions & 5 deletions app/src/main/java/com/kickstarter/ui/activities/ThreadActivity.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
package com.kickstarter.ui.activities

import android.os.Bundle
import android.view.ViewGroup
import androidx.activity.addCallback
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.ViewCompat
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.recyclerview.widget.ConcatAdapter
import androidx.recyclerview.widget.LinearLayoutManager
import com.kickstarter.R
Expand All @@ -22,7 +28,6 @@ import com.kickstarter.ui.adapters.RepliesStatusAdapter
import com.kickstarter.ui.adapters.RootCommentAdapter
import com.kickstarter.ui.extensions.hideKeyboard
import com.kickstarter.ui.views.OnCommentComposerViewClickedListener
import com.kickstarter.utils.WindowInsetsUtil
import com.kickstarter.viewmodels.ThreadViewModel
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
Expand Down Expand Up @@ -58,13 +63,27 @@ class ThreadActivity :

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
WindowCompat.setDecorFitsSystemWindows(window, false)

binding = ActivityThreadLayoutBinding.inflate(layoutInflater)
WindowInsetsUtil.manageEdgeToEdge(
window,
binding.root
)
setContentView(binding.root)

ViewCompat.setOnApplyWindowInsetsListener(binding.root) { v, windowInsets ->
val insets = windowInsets.getInsets(WindowInsetsCompat.Type.systemBars())
v.updateLayoutParams<ViewGroup.MarginLayoutParams> {
// Apply the left, right, top, and bottom margins based on the insets
leftMargin = insets.left
bottomMargin = insets.bottom
rightMargin = insets.right
topMargin = insets.top
}

val imeInsets = windowInsets.getInsets(WindowInsetsCompat.Type.ime())
v.updatePadding(bottom = imeInsets.bottom)

WindowInsetsCompat.CONSUMED
}

val environment = this.getEnvironment()?.let { env ->
viewModelFactory = ThreadViewModel.Factory(env)
ksString = requireNotNull(env.ksString())
Expand Down
2 changes: 1 addition & 1 deletion app/src/main/res/layout/messages_layout.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
android:id="@+id/messages_coordinator_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
android:fitsSystemWindows="false">

<com.google.android.material.appbar.AppBarLayout
android:id="@+id/messages_app_bar_layout"
Expand Down

0 comments on commit 13f486f

Please sign in to comment.