From e8d26222b913accb9d7c576ea7b922cbe9a4a6cb Mon Sep 17 00:00:00 2001 From: Andrew Date: Tue, 30 May 2023 11:44:20 +0930 Subject: [PATCH] Fix scroll to bottom button visibility (#1219) --- .../conversation/v2/ConversationActivityV2.kt | 46 +++++++++++-------- .../session/libsession/utilities/ViewUtils.kt | 3 +- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt index f9385d14bcc..07751cab9a0 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/conversation/v2/ConversationActivityV2.kt @@ -21,7 +21,6 @@ import android.widget.Toast import androidx.activity.viewModels import androidx.annotation.DimenRes import androidx.appcompat.app.AlertDialog -import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.lifecycle.Observer import androidx.lifecycle.ViewModelProvider @@ -210,6 +209,8 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe val searchViewModel: SearchViewModel by viewModels() var searchViewItem: MenuItem? = null + private var emojiPickerVisible = false + private val isScrolledToBottom: Boolean get() = binding?.conversationRecyclerView?.isScrolledToBottom ?: true @@ -441,17 +442,22 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe handleRecyclerViewScrolled() } }) + + binding!!.conversationRecyclerView.addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> + showScrollToBottomButtonIfApplicable() + } } // called from onCreate private fun setUpToolBar() { - setSupportActionBar(binding?.toolbar) + val binding = binding ?: return + setSupportActionBar(binding.toolbar) val actionBar = supportActionBar ?: return val recipient = viewModel.recipient ?: return actionBar.title = "" actionBar.setDisplayHomeAsUpEnabled(true) actionBar.setHomeButtonEnabled(true) - binding!!.toolbarContent.conversationTitleView.text = when { + binding.toolbarContent.conversationTitleView.text = when { recipient.isLocalNumber -> getString(R.string.note_to_self) else -> recipient.toShortString() } @@ -461,13 +467,11 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe R.dimen.small_profile_picture_size } val size = resources.getDimension(sizeID).roundToInt() - binding!!.toolbarContent.profilePictureView.root.layoutParams = LinearLayout.LayoutParams(size, size) - binding!!.toolbarContent.profilePictureView.root.glide = glide + binding.toolbarContent.profilePictureView.root.layoutParams = LinearLayout.LayoutParams(size, size) + binding.toolbarContent.profilePictureView.root.glide = glide MentionManagerUtilities.populateUserPublicKeyCacheIfNeeded(viewModel.threadId, this) - val profilePictureView = binding!!.toolbarContent.profilePictureView.root - viewModel.recipient?.let { recipient -> - profilePictureView.update(recipient) - } + val profilePictureView = binding.toolbarContent.profilePictureView.root + viewModel.recipient?.let(profilePictureView::update) } // called from onCreate @@ -904,15 +908,14 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe val binding = binding ?: return val wasTypingIndicatorVisibleBefore = binding.typingIndicatorViewContainer.isVisible binding.typingIndicatorViewContainer.isVisible = wasTypingIndicatorVisibleBefore && isScrolledToBottom - binding.typingIndicatorViewContainer.isVisible - showOrHidScrollToBottomButton() + showScrollToBottomButtonIfApplicable() val firstVisiblePosition = layoutManager?.findFirstVisibleItemPosition() ?: -1 unreadCount = min(unreadCount, firstVisiblePosition).coerceAtLeast(0) updateUnreadCountIndicator() } - private fun showOrHidScrollToBottomButton(show: Boolean = true) { - binding?.scrollToBottomButton?.isVisible = show && !isScrolledToBottom && adapter.itemCount > 0 + private fun showScrollToBottomButtonIfApplicable() { + binding?.scrollToBottomButton?.isVisible = !emojiPickerVisible && !isScrolledToBottom && adapter.itemCount > 0 } private fun updateUnreadCountIndicator() { @@ -1084,21 +1087,26 @@ class ConversationActivityV2 : PassphraseRequiredActionBarActivity(), InputBarDe Log.e("Loki", "Failed to show emoji picker", e) return } + + val binding = binding ?: return + + emojiPickerVisible = true ViewUtil.hideKeyboard(this, visibleMessageView) - binding?.reactionsShade?.isVisible = true - showOrHidScrollToBottomButton(false) - binding?.conversationRecyclerView?.suppressLayout(true) + binding.reactionsShade.isVisible = true + binding.scrollToBottomButton.isVisible = false + binding.conversationRecyclerView.suppressLayout(true) reactionDelegate.setOnActionSelectedListener(ReactionsToolbarListener(message)) reactionDelegate.setOnHideListener(object: ConversationReactionOverlay.OnHideListener { override fun startHide() { - binding?.reactionsShade?.let { + emojiPickerVisible = false + binding.reactionsShade.let { ViewUtil.fadeOut(it, resources.getInteger(R.integer.reaction_scrubber_hide_duration), View.GONE) } - showOrHidScrollToBottomButton(true) + showScrollToBottomButtonIfApplicable() } override fun onHide() { - binding?.conversationRecyclerView?.suppressLayout(false) + binding.conversationRecyclerView.suppressLayout(false) WindowUtil.setLightStatusBarFromTheme(this@ConversationActivityV2); WindowUtil.setLightNavigationBarFromTheme(this@ConversationActivityV2); diff --git a/libsession/src/main/java/org/session/libsession/utilities/ViewUtils.kt b/libsession/src/main/java/org/session/libsession/utilities/ViewUtils.kt index ea4932d05ce..dfe0c3b4513 100644 --- a/libsession/src/main/java/org/session/libsession/utilities/ViewUtils.kt +++ b/libsession/src/main/java/org/session/libsession/utilities/ViewUtils.kt @@ -5,6 +5,7 @@ import android.util.TypedValue import androidx.annotation.AttrRes import androidx.annotation.ColorInt import androidx.recyclerview.widget.RecyclerView +import kotlin.math.max @ColorInt fun Context.getColorFromAttr( @@ -17,4 +18,4 @@ fun Context.getColorFromAttr( } val RecyclerView.isScrolledToBottom: Boolean - get() = computeVerticalScrollOffset() + computeVerticalScrollExtent() >= computeVerticalScrollRange() + get() = max(0, computeVerticalScrollOffset()) + computeVerticalScrollExtent() >= computeVerticalScrollRange()