fix window insets related bugs (#4978)

- Fixes the background of the ComposeActivity in table mode which looked
weird since https://github.com/tuskyapp/Tusky/pull/4897
- The ComposeActivity in tablet mode will now resize when the keyboard
expands, the previously used fixed height would cause the bottom bar to
hide entered text on some devices, closes
https://github.com/tuskyapp/Tusky/issues/4973
- The bottom sheets in the compose view will now be in fully hidden
state by default, as some weirdness on some devices caused them to peek
over the bottom bar in half collapsed state. Please test @fin-w
- The bottom sheet in the image viewer will now expand a bit more in
edge-to-edge mode so it doesn't look it is deliberately obscured by the
system bar. The image also moves up a bit so it won't be covered by the
bottom sheet as much.
- The "Performing lookup…" bottom sheet won't be covered by the nav bar
anymore
This commit is contained in:
Konrad Pozniak 2025-03-08 09:08:09 +01:00 committed by GitHub
commit b03279a2e2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 103 additions and 62 deletions

View file

@ -132,26 +132,30 @@ abstract class BaseActivity : AppCompatActivity() {
override fun onPostCreate(savedInstanceState: Bundle?) {
super.onPostCreate(savedInstanceState)
window.decorView.setBackgroundColor(Color.BLACK)
val contentView: View = findViewById(android.R.id.content)
contentView.setBackgroundColor(MaterialColors.getColor(contentView, android.R.attr.colorBackground))
// currently only ComposeActivity on tablets is floating
if (!window.isFloating) {
window.decorView.setBackgroundColor(Color.BLACK)
// handle left/right insets. This is relevant for edge-to-edge mode in landscape orientation
ViewCompat.setOnApplyWindowInsetsListener(contentView) { _, insets ->
val systemBarInsets = insets.getInsets(systemBars())
val displayCutoutInsets = insets.getInsets(displayCutout())
// use padding for system bar insets so they get our background color and margin for cutout insets to turn them black
contentView.updatePadding(left = systemBarInsets.left, right = systemBarInsets.right)
contentView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
leftMargin = displayCutoutInsets.left
rightMargin = displayCutoutInsets.right
val contentView: View = findViewById(android.R.id.content)
contentView.setBackgroundColor(MaterialColors.getColor(contentView, android.R.attr.colorBackground))
// handle left/right insets. This is relevant for edge-to-edge mode in landscape orientation
ViewCompat.setOnApplyWindowInsetsListener(contentView) { _, insets ->
val systemBarInsets = insets.getInsets(systemBars())
val displayCutoutInsets = insets.getInsets(displayCutout())
// use padding for system bar insets so they get our background color and margin for cutout insets to turn them black
contentView.updatePadding(left = systemBarInsets.left, right = systemBarInsets.right)
contentView.updateLayoutParams<ViewGroup.MarginLayoutParams> {
leftMargin = displayCutoutInsets.left
rightMargin = displayCutoutInsets.right
}
WindowInsetsCompat.Builder(insets)
.setInsets(systemBars(), Insets.of(0, systemBarInsets.top, 0, systemBarInsets.bottom))
.setInsets(displayCutout(), Insets.of(0, displayCutoutInsets.top, 0, displayCutoutInsets.bottom))
.build()
}
WindowInsetsCompat.Builder(insets)
.setInsets(systemBars(), Insets.of(0, systemBarInsets.top, 0, systemBarInsets.bottom))
.setInsets(displayCutout(), Insets.of(0, displayCutoutInsets.top, 0, displayCutoutInsets.bottom))
.build()
}
}

View file

@ -22,6 +22,10 @@ import android.view.View
import android.widget.LinearLayout
import android.widget.Toast
import androidx.annotation.VisibleForTesting
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat.Type.ime
import androidx.core.view.WindowInsetsCompat.Type.systemBars
import androidx.core.view.updatePadding
import androidx.lifecycle.lifecycleScope
import at.connyduck.calladapter.networkresult.fold
import com.google.android.material.bottomsheet.BottomSheetBehavior
@ -62,6 +66,14 @@ abstract class BottomSheetActivity : BaseActivity() {
override fun onSlide(bottomSheet: View, slideOffset: Float) {}
})
ViewCompat.setOnApplyWindowInsetsListener(bottomSheetLayout) { _, insets ->
val systemBarsInsets = insets.getInsets(systemBars() or ime())
val bottomInsets = systemBarsInsets.bottom
bottomSheetLayout.updatePadding(bottom = bottomInsets)
insets
}
}
open fun viewUrl(

View file

@ -54,6 +54,7 @@ import androidx.core.view.WindowInsetsCompat.Type.ime
import androidx.core.view.WindowInsetsCompat.Type.systemBars
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.core.widget.doAfterTextChanged
import androidx.core.widget.doOnTextChanged
@ -265,12 +266,14 @@ class ComposeActivity :
binding.composeBottomBar.setOnWindowInsetsChangeListener { windowInsets ->
val insets = windowInsets.getInsets(systemBars() or ime())
binding.composeBottomBar.updatePadding(bottom = insets.bottom + at.connyduck.sparkbutton.helpers.Utils.dpToPx(this@ComposeActivity, 4))
binding.addMediaBottomSheet.updatePadding(bottom = insets.bottom + at.connyduck.sparkbutton.helpers.Utils.dpToPx(this@ComposeActivity, 50))
binding.emojiView.updatePadding(bottom = insets.bottom + at.connyduck.sparkbutton.helpers.Utils.dpToPx(this@ComposeActivity, 50))
binding.composeOptionsBottomSheet.updatePadding(bottom = insets.bottom + at.connyduck.sparkbutton.helpers.Utils.dpToPx(this@ComposeActivity, 50))
binding.composeScheduleView.updatePadding(bottom = insets.bottom + at.connyduck.sparkbutton.helpers.Utils.dpToPx(this@ComposeActivity, 50))
(binding.composeMainScrollView.layoutParams as ViewGroup.MarginLayoutParams).bottomMargin = insets.bottom + at.connyduck.sparkbutton.helpers.Utils.dpToPx(this@ComposeActivity, 58)
val bottomBarHeight = resources.getDimensionPixelSize(R.dimen.compose_bottom_bar_height)
val bottomBarPadding = resources.getDimensionPixelSize(R.dimen.compose_bottom_bar_padding_vertical)
binding.composeBottomBar.updatePadding(bottom = insets.bottom + bottomBarPadding)
binding.addMediaBottomSheet.updatePadding(bottom = insets.bottom + bottomBarHeight)
binding.emojiView.updatePadding(bottom = insets.bottom + bottomBarHeight)
binding.composeOptionsBottomSheet.updatePadding(bottom = insets.bottom + bottomBarHeight)
binding.composeScheduleView.updatePadding(bottom = insets.bottom + bottomBarHeight)
binding.composeMainScrollView.updateLayoutParams<ViewGroup.MarginLayoutParams> { bottomMargin = insets.bottom + bottomBarHeight }
}
setupActionBar()
@ -610,6 +613,11 @@ class ComposeActivity :
scheduleBehavior = BottomSheetBehavior.from(binding.composeScheduleView)
emojiBehavior = BottomSheetBehavior.from(binding.emojiView)
composeOptionsBehavior.state = BottomSheetBehavior.STATE_HIDDEN
addMediaBehavior.state = BottomSheetBehavior.STATE_HIDDEN
scheduleBehavior.state = BottomSheetBehavior.STATE_HIDDEN
emojiBehavior.state = BottomSheetBehavior.STATE_HIDDEN
val bottomSheetCallback = object : BottomSheetCallback() {
override fun onStateChanged(bottomSheet: View, newState: Int) {
updateOnBackPressedCallbackState()
@ -1005,11 +1013,11 @@ class ComposeActivity :
override fun onSlide(bottomSheet: View, slideOffset: Float) {}
}
)
addMediaBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
addMediaBehavior.state = BottomSheetBehavior.STATE_HIDDEN
}
private fun openPollDialog() = lifecycleScope.launch {
addMediaBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
addMediaBehavior.state = BottomSheetBehavior.STATE_HIDDEN
val instanceParams = viewModel.instanceInfo.first()
showAddPollDialog(
context = this@ComposeActivity,
@ -1058,7 +1066,7 @@ class ComposeActivity :
}
override fun onVisibilityChanged(visibility: Status.Visibility) {
composeOptionsBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
composeOptionsBehavior.state = BottomSheetBehavior.STATE_HIDDEN
viewModel.changeStatusVisibility(visibility)
}
@ -1165,7 +1173,7 @@ class ComposeActivity :
}
private fun initiateCameraApp() {
addMediaBehavior.state = BottomSheetBehavior.STATE_COLLAPSED
addMediaBehavior.state = BottomSheetBehavior.STATE_HIDDEN
val photoFile: File = try {
createNewImageFile(this)

View file

@ -29,6 +29,7 @@ import android.view.ViewGroup
import android.widget.ImageView
import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat.Type.systemBars
import androidx.core.view.updateLayoutParams
import androidx.core.view.updatePadding
import androidx.lifecycle.lifecycleScope
import com.bumptech.glide.Glide
@ -36,6 +37,7 @@ import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.GlideException
import com.bumptech.glide.request.RequestListener
import com.bumptech.glide.request.target.Target
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.keylesspalace.tusky.R
import com.keylesspalace.tusky.databinding.FragmentViewImageBinding
import com.keylesspalace.tusky.entity.Attachment
@ -110,12 +112,17 @@ class ViewImageFragment : ViewMediaFragment() {
}
}
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, insets ->
val systemBarInsets = insets.getInsets(systemBars())
val mediaDescriptionBottomPadding = requireContext().resources.getDimensionPixelSize(R.dimen.media_description_sheet_bottom_padding)
binding.mediaDescription.updatePadding(bottom = mediaDescriptionBottomPadding + systemBarInsets.bottom)
val descriptionBottomSheet = BottomSheetBehavior.from(binding.captionSheet)
insets.inset(0, 0, 0, systemBarInsets.bottom)
ViewCompat.setOnApplyWindowInsetsListener(binding.root) { _, insets ->
val bottomInsets = insets.getInsets(systemBars()).bottom
val mediaDescriptionBottomPadding = requireContext().resources.getDimensionPixelSize(R.dimen.media_description_sheet_bottom_padding)
val mediaDescriptionPeekHeight = requireContext().resources.getDimensionPixelSize(R.dimen.media_description_sheet_peek_height)
val imageViewBottomMargin = requireContext().resources.getDimensionPixelSize(R.dimen.media_image_view_bottom_margin)
binding.mediaDescription.updatePadding(bottom = mediaDescriptionBottomPadding + bottomInsets)
descriptionBottomSheet.setPeekHeight(mediaDescriptionPeekHeight + bottomInsets, false)
binding.photoView.updateLayoutParams<ViewGroup.MarginLayoutParams> { bottomMargin = imageViewBottomMargin + bottomInsets }
insets.inset(0, 0, 0, bottomInsets)
}
val singleTapDetector = GestureDetector(

View file

@ -1,5 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<corners android:radius="16dp" />
<solid android:color="?android:attr/colorBackground" />
</shape>
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetTop="@dimen/dialog_activity_vertical_inset"
android:insetBottom="@dimen/dialog_activity_vertical_inset">
<shape>
<corners android:radius="16dp" />
<solid android:color="?android:attr/colorBackground" />
</shape>
</inset>

View file

@ -82,10 +82,11 @@
<androidx.core.widget.NestedScrollView
android:id="@+id/composeMainScrollView"
android:layout_width="match_parent"
android:layout_height="@dimen/compose_activity_scrollview_height"
android:layout_marginBottom="52dp"
android:layout_height="match_parent"
android:layout_marginBottom="@dimen/compose_bottom_bar_height"
android:clipToPadding="false"
android:paddingTop="8dp"
android:paddingBottom="8dp"
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
<LinearLayout
@ -152,6 +153,7 @@
android:inputType="text|textCapSentences"
android:lineSpacingMultiplier="1.1"
android:maxLines="1"
android:nestedScrollingEnabled="false"
android:paddingLeft="16dp"
android:paddingRight="16dp"
android:textColorHint="?android:attr/textColorTertiary"
@ -175,6 +177,7 @@
android:hint="@string/hint_compose"
android:inputType="text|textMultiLine|textCapSentences"
android:lineSpacingMultiplier="1.1"
android:nestedScrollingEnabled="false"
android:paddingLeft="16dp"
android:paddingTop="8dp"
android:paddingRight="16dp"
@ -211,7 +214,7 @@
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:paddingBottom="52dp"
android:paddingBottom="@dimen/compose_bottom_bar_height"
app:behavior_hideable="true"
app:behavior_peekHeight="0dp"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
@ -242,6 +245,7 @@
android:padding="8dp"
android:text="@string/action_add_poll"
android:textSize="?attr/status_text_medium" />
</LinearLayout>
<com.keylesspalace.tusky.view.EmojiPicker
@ -253,7 +257,7 @@
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:paddingBottom="60dp"
android:paddingBottom="@dimen/compose_bottom_bar_height"
app:behavior_hideable="true"
app:behavior_peekHeight="0dp"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior" />
@ -267,7 +271,7 @@
android:paddingStart="24dp"
android:paddingTop="12dp"
android:paddingEnd="24dp"
android:paddingBottom="60dp"
android:paddingBottom="@dimen/compose_bottom_bar_height"
app:behavior_hideable="true"
app:behavior_peekHeight="0dp"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior" />
@ -281,7 +285,7 @@
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="16dp"
android:paddingBottom="52dp"
android:paddingBottom="@dimen/compose_bottom_bar_height"
app:behavior_hideable="true"
app:behavior_peekHeight="0dp"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior" />
@ -291,15 +295,13 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:animateLayoutChanges="true"
android:background="?attr/colorSurface"
android:elevation="12dp"
android:gravity="center_vertical"
android:paddingStart="8dp"
android:paddingTop="4dp"
android:paddingEnd="8dp"
android:paddingBottom="4dp"
app:layout_insetEdge="bottom">
android:paddingStart="@dimen/compose_bottom_bar_padding_horizontal"
android:paddingTop="@dimen/compose_bottom_bar_padding_vertical"
android:paddingEnd="@dimen/compose_bottom_bar_padding_horizontal"
android:paddingBottom="@dimen/compose_bottom_bar_padding_vertical">
<ImageButton
android:id="@+id/composeAddMediaButton"

View file

@ -10,7 +10,8 @@
<com.ortiz.touchview.TouchImageView
android:id="@+id/photoView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
android:layout_height="match_parent"
android:layout_marginBottom="@dimen/media_image_view_bottom_margin"/>
<com.google.android.material.progressindicator.CircularProgressIndicator
android:id="@+id/progressBar"
@ -45,7 +46,7 @@
android:layout_height="wrap_content"
android:background="@drawable/description_bg_expanded"
android:orientation="vertical"
app:behavior_peekHeight="90dp"
app:behavior_peekHeight="@dimen/media_description_sheet_peek_height"
app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior">
<View

View file

@ -3,7 +3,7 @@
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/item_status_bottom_sheet"
android:layout_width="match_parent"
android:layout_height="80dp"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:background="?android:colorBackground"
android:orientation="vertical"
@ -14,7 +14,9 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:paddingVertical="24dp"
android:text="@string/performing_lookup_title"
android:textColor="?android:textColorPrimary"
android:textSize="?attr/status_text_medium" />
</LinearLayout>
</LinearLayout>

View file

@ -1,3 +1,3 @@
<resources>
<dimen name="compose_activity_scrollview_height">180dp</dimen>
<dimen name="dialog_activity_vertical_inset">16dp</dimen>
</resources>

View file

@ -1,6 +1,4 @@
<resources>
<dimen name="compose_activity_scrollview_height">400dp</dimen>
<dimen name="status_media_preview_height">160dp</dimen>
<dimen name="status_detail_media_preview_height">180dp</dimen>
</resources>

View file

@ -4,11 +4,9 @@
<item name="android:windowBackground">@drawable/background_dialog_activity</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
<item name="android:windowSoftInputMode">stateAlwaysVisible|adjustResize</item>
<item name="android:windowCloseOnTouchOutside">false</item>
<item name="android:windowActionModeOverlay">true</item>
<item name="android:windowMinWidthMajor">80%</item>
<item name="android:windowMinWidthMinor">80%</item>
</style>
<style name="TuskyDialogActivityBlackTheme" parent="@style/TuskyBlackTheme">
@ -16,11 +14,9 @@
<item name="android:windowBackground">@drawable/background_dialog_activity</item>
<item name="android:windowIsFloating">true</item>
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowSoftInputMode">stateUnspecified|adjustPan</item>
<item name="android:windowSoftInputMode">stateAlwaysVisible|adjustResize</item>
<item name="android:windowCloseOnTouchOutside">false</item>
<item name="android:windowActionModeOverlay">true</item>
<item name="android:windowMinWidthMajor">80%</item>
<item name="android:windowMinWidthMinor">80%</item>
</style>
</resources>

View file

@ -21,7 +21,6 @@
<dimen name="account_activity_scroll_title_visible_height">200dp</dimen>
<dimen name="account_activity_avatar_size">100dp</dimen>
<dimen name="compose_activity_scrollview_height">-1px</dimen> <!-- match_parent -->
<dimen name="timeline_width">-1px</dimen> <!-- match_parent -->
<item name="wrap_content" format="integer" type="dimen">-2</item>
@ -83,6 +82,8 @@
<dimen name="dialog_inset">24dp</dimen>
<dimen name="media_description_sheet_bottom_padding">8dp</dimen>
<dimen name="media_description_sheet_peek_height">90dp</dimen>
<dimen name="media_image_view_bottom_margin">24dp</dimen>
<dimen name="bottomAppBarHeight">64dp</dimen>
@ -94,4 +95,10 @@
<dimen name="status_info_drawable_padding_small">6dp</dimen>
<dimen name="status_info_padding_small">38dp</dimen>
<dimen name="compose_bottom_bar_height">56dp</dimen>
<dimen name="compose_bottom_bar_padding_vertical">4dp</dimen>
<dimen name="compose_bottom_bar_padding_horizontal">8dp</dimen>
<dimen name="dialog_activity_vertical_inset">64dp</dimen>
</resources>