kopia lustrzana https://github.com/ryukoposting/Signal-Android
Fix emoji keyboard bugs and group story replies.
rodzic
b8bb2e234b
commit
11c3ea769e
|
@ -0,0 +1,14 @@
|
||||||
|
package com.google.android.material.bottomsheet
|
||||||
|
|
||||||
|
import android.view.View
|
||||||
|
import android.widget.FrameLayout
|
||||||
|
import java.lang.ref.WeakReference
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manually adjust the nested scrolling child for a given [BottomSheetBehavior].
|
||||||
|
*/
|
||||||
|
object BottomSheetBehaviorHack {
|
||||||
|
fun setNestedScrollingChild(behavior: BottomSheetBehavior<FrameLayout>, view: View) {
|
||||||
|
behavior.nestedScrollingChildRef = WeakReference(view)
|
||||||
|
}
|
||||||
|
}
|
|
@ -146,6 +146,10 @@ public class MediaKeyboard extends FrameLayout implements InputView {
|
||||||
.commitAllowingStateLoss();
|
.commitAllowingStateLoss();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isEmojiSearchMode() {
|
||||||
|
return keyboardState == State.EMOJI_SEARCH;
|
||||||
|
}
|
||||||
|
|
||||||
private void initView() {
|
private void initView() {
|
||||||
if (!isInitialised) {
|
if (!isInitialised) {
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ import org.thoughtcrime.securesms.R
|
||||||
import org.thoughtcrime.securesms.components.ComposeText
|
import org.thoughtcrime.securesms.components.ComposeText
|
||||||
import org.thoughtcrime.securesms.components.InputAwareLayout
|
import org.thoughtcrime.securesms.components.InputAwareLayout
|
||||||
import org.thoughtcrime.securesms.components.QuoteView
|
import org.thoughtcrime.securesms.components.QuoteView
|
||||||
|
import org.thoughtcrime.securesms.components.emoji.EmojiPageView
|
||||||
import org.thoughtcrime.securesms.components.emoji.EmojiToggle
|
import org.thoughtcrime.securesms.components.emoji.EmojiToggle
|
||||||
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard
|
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard
|
||||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
|
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
|
||||||
|
@ -42,6 +43,9 @@ class StoryReplyComposer @JvmOverloads constructor(
|
||||||
|
|
||||||
var callback: Callback? = null
|
var callback: Callback? = null
|
||||||
|
|
||||||
|
val emojiPageView: EmojiPageView?
|
||||||
|
get() = findViewById(R.id.emoji_page_view)
|
||||||
|
|
||||||
init {
|
init {
|
||||||
inflate(context, R.layout.stories_reply_to_story_composer, this)
|
inflate(context, R.layout.stories_reply_to_story_composer, this)
|
||||||
|
|
||||||
|
@ -85,6 +89,12 @@ class StoryReplyComposer @JvmOverloads constructor(
|
||||||
emojiDrawerToggle.setOnClickListener {
|
emojiDrawerToggle.setOnClickListener {
|
||||||
onEmojiToggleClicked()
|
onEmojiToggleClicked()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inputAwareLayout.addOnKeyboardShownListener {
|
||||||
|
if (inputAwareLayout.currentInput == emojiDrawer && !emojiDrawer.isEmojiSearchMode) {
|
||||||
|
onEmojiToggleClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setQuote(messageRecord: MediaMmsMessageRecord) {
|
fun setQuote(messageRecord: MediaMmsMessageRecord) {
|
||||||
|
@ -136,11 +146,13 @@ class StoryReplyComposer @JvmOverloads constructor(
|
||||||
if (inputAwareLayout.currentInput == emojiDrawer) {
|
if (inputAwareLayout.currentInput == emojiDrawer) {
|
||||||
isRequestingEmojiDrawer = false
|
isRequestingEmojiDrawer = false
|
||||||
inputAwareLayout.showSoftkey(input)
|
inputAwareLayout.showSoftkey(input)
|
||||||
|
callback?.onHideEmojiKeyboard()
|
||||||
} else {
|
} else {
|
||||||
isRequestingEmojiDrawer = true
|
isRequestingEmojiDrawer = true
|
||||||
inputAwareLayout.hideSoftkey(input) {
|
inputAwareLayout.hideSoftkey(input) {
|
||||||
inputAwareLayout.post {
|
inputAwareLayout.post {
|
||||||
inputAwareLayout.show(input, emojiDrawer)
|
inputAwareLayout.show(input, emojiDrawer)
|
||||||
|
emojiDrawer.post { callback?.onShowEmojiKeyboard() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -150,6 +162,8 @@ class StoryReplyComposer @JvmOverloads constructor(
|
||||||
fun onSendActionClicked()
|
fun onSendActionClicked()
|
||||||
fun onPickReactionClicked()
|
fun onPickReactionClicked()
|
||||||
fun onInitializeEmojiDrawer(mediaKeyboard: MediaKeyboard)
|
fun onInitializeEmojiDrawer(mediaKeyboard: MediaKeyboard)
|
||||||
|
fun onShowEmojiKeyboard() = Unit
|
||||||
|
fun onHideEmojiKeyboard() = Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -37,6 +37,8 @@ class StoryGroupReplyBottomSheetDialogFragment : FixedRoundedCornerBottomSheetDi
|
||||||
override val peekHeightPercentage: Float = 1f
|
override val peekHeightPercentage: Float = 1f
|
||||||
|
|
||||||
private val lifecycleDisposable = LifecycleDisposable()
|
private val lifecycleDisposable = LifecycleDisposable()
|
||||||
|
private var shouldShowFullScreen = false
|
||||||
|
private var initialParentHeight = 0
|
||||||
|
|
||||||
private val storyViewerPageViewModel: StoryViewerPageViewModel by viewModels(
|
private val storyViewerPageViewModel: StoryViewerPageViewModel by viewModels(
|
||||||
ownerProducer = { requireParentFragment() }
|
ownerProducer = { requireParentFragment() }
|
||||||
|
@ -70,7 +72,16 @@ class StoryGroupReplyBottomSheetDialogFragment : FixedRoundedCornerBottomSheetDi
|
||||||
view.viewTreeObserver.addOnGlobalLayoutListener {
|
view.viewTreeObserver.addOnGlobalLayoutListener {
|
||||||
val parentHeight = requireCoordinatorLayout().height
|
val parentHeight = requireCoordinatorLayout().height
|
||||||
val desiredHeight = (resources.displayMetrics.heightPixels * 0.6f).roundToInt()
|
val desiredHeight = (resources.displayMetrics.heightPixels * 0.6f).roundToInt()
|
||||||
val targetHeight = if (parentHeight != 0) min(parentHeight, desiredHeight) else desiredHeight
|
|
||||||
|
if (initialParentHeight == 0) {
|
||||||
|
initialParentHeight = parentHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
val targetHeight = when {
|
||||||
|
parentHeight == 0 -> desiredHeight
|
||||||
|
shouldShowFullScreen || parentHeight != initialParentHeight -> parentHeight
|
||||||
|
else -> min(parentHeight, desiredHeight)
|
||||||
|
}
|
||||||
|
|
||||||
if (view.height != targetHeight) {
|
if (view.height != targetHeight) {
|
||||||
view.updateLayoutParams {
|
view.updateLayoutParams {
|
||||||
|
@ -90,6 +101,11 @@ class StoryGroupReplyBottomSheetDialogFragment : FixedRoundedCornerBottomSheetDi
|
||||||
storyViewerPageViewModel.startDirectReply(storyId, recipientId)
|
storyViewerPageViewModel.startDirectReply(storyId, recipientId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun requestFullScreen(fullscreen: Boolean) {
|
||||||
|
shouldShowFullScreen = fullscreen
|
||||||
|
requireView().invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val ARG_STORY_ID = "arg.story.id"
|
private const val ARG_STORY_ID = "arg.story.id"
|
||||||
private const val ARG_GROUP_RECIPIENT_ID = "arg.group.recipient.id"
|
private const val ARG_GROUP_RECIPIENT_ID = "arg.group.recipient.id"
|
||||||
|
|
|
@ -2,19 +2,22 @@ package org.thoughtcrime.securesms.stories.viewer.reply.group
|
||||||
|
|
||||||
import android.content.ClipData
|
import android.content.ClipData
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.provider.Settings.System.getConfiguration
|
|
||||||
import android.view.KeyEvent
|
import android.view.KeyEvent
|
||||||
|
import android.view.MotionEvent
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
import androidx.recyclerview.widget.LinearLayoutManager
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
import androidx.recyclerview.widget.RecyclerView
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetBehaviorHack
|
||||||
|
import com.google.android.material.bottomsheet.BottomSheetDialog
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
import io.reactivex.rxjava3.kotlin.subscribeBy
|
import io.reactivex.rxjava3.kotlin.subscribeBy
|
||||||
import org.signal.core.util.concurrent.SignalExecutors
|
import org.signal.core.util.concurrent.SignalExecutors
|
||||||
import org.signal.core.util.logging.Log
|
import org.signal.core.util.logging.Log
|
||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
|
import org.thoughtcrime.securesms.components.FixedRoundedCornerBottomSheetDialogFragment
|
||||||
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard
|
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard
|
||||||
import org.thoughtcrime.securesms.components.mention.MentionAnnotation
|
import org.thoughtcrime.securesms.components.mention.MentionAnnotation
|
||||||
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
|
||||||
|
@ -72,6 +75,18 @@ class StoryGroupReplyFragment :
|
||||||
ownerProducer = { requireActivity() }
|
ownerProducer = { requireActivity() }
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val recyclerListener: RecyclerView.OnItemTouchListener = object : RecyclerView.SimpleOnItemTouchListener() {
|
||||||
|
override fun onInterceptTouchEvent(view: RecyclerView, e: MotionEvent): Boolean {
|
||||||
|
recyclerView.isNestedScrollingEnabled = view == recyclerView
|
||||||
|
composer.emojiPageView?.isNestedScrollingEnabled = view == composer.emojiPageView
|
||||||
|
|
||||||
|
val dialog = (parentFragment as FixedRoundedCornerBottomSheetDialogFragment).dialog as BottomSheetDialog
|
||||||
|
BottomSheetBehaviorHack.setNestedScrollingChild(dialog.behavior, view)
|
||||||
|
dialog.findViewById<View>(R.id.design_bottom_sheet)?.invalidate()
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private val colorizer = Colorizer()
|
private val colorizer = Colorizer()
|
||||||
private val lifecycleDisposable = LifecycleDisposable()
|
private val lifecycleDisposable = LifecycleDisposable()
|
||||||
|
|
||||||
|
@ -245,6 +260,18 @@ class StoryGroupReplyFragment :
|
||||||
mediaKeyboard.setFragmentManager(childFragmentManager)
|
mediaKeyboard.setFragmentManager(childFragmentManager)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun onShowEmojiKeyboard() {
|
||||||
|
requireListener<Callback>().requestFullScreen(true)
|
||||||
|
recyclerView.addOnItemTouchListener(recyclerListener)
|
||||||
|
composer.emojiPageView?.addOnItemTouchListener(recyclerListener)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onHideEmojiKeyboard() {
|
||||||
|
recyclerView.removeOnItemTouchListener(recyclerListener)
|
||||||
|
composer.emojiPageView?.removeOnItemTouchListener(recyclerListener)
|
||||||
|
requireListener<Callback>().requestFullScreen(false)
|
||||||
|
}
|
||||||
|
|
||||||
override fun openEmojiSearch() {
|
override fun openEmojiSearch() {
|
||||||
composer.openEmojiSearch()
|
composer.openEmojiSearch()
|
||||||
}
|
}
|
||||||
|
@ -359,5 +386,6 @@ class StoryGroupReplyFragment :
|
||||||
|
|
||||||
interface Callback {
|
interface Callback {
|
||||||
fun onStartDirectReply(recipientId: RecipientId)
|
fun onStartDirectReply(recipientId: RecipientId)
|
||||||
|
fun requestFullScreen(fullscreen: Boolean)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,6 +48,9 @@ class StoryViewsAndRepliesDialogFragment : FixedRoundedCornerBottomSheetDialogFr
|
||||||
|
|
||||||
private lateinit var pager: ViewPager2
|
private lateinit var pager: ViewPager2
|
||||||
|
|
||||||
|
private var shouldShowFullScreen = false
|
||||||
|
private var initialParentHeight = 0
|
||||||
|
|
||||||
private val storyViewerPageViewModel: StoryViewerPageViewModel by viewModels(
|
private val storyViewerPageViewModel: StoryViewerPageViewModel by viewModels(
|
||||||
ownerProducer = { requireParentFragment() }
|
ownerProducer = { requireParentFragment() }
|
||||||
)
|
)
|
||||||
|
@ -96,7 +99,16 @@ class StoryViewsAndRepliesDialogFragment : FixedRoundedCornerBottomSheetDialogFr
|
||||||
view.viewTreeObserver.addOnGlobalLayoutListener {
|
view.viewTreeObserver.addOnGlobalLayoutListener {
|
||||||
val parentHeight = requireCoordinatorLayout().height
|
val parentHeight = requireCoordinatorLayout().height
|
||||||
val desiredHeight = (resources.displayMetrics.heightPixels * 0.6f).roundToInt()
|
val desiredHeight = (resources.displayMetrics.heightPixels * 0.6f).roundToInt()
|
||||||
val targetHeight = if (parentHeight != 0) min(parentHeight, desiredHeight) else desiredHeight
|
|
||||||
|
if (initialParentHeight == 0) {
|
||||||
|
initialParentHeight = parentHeight
|
||||||
|
}
|
||||||
|
|
||||||
|
val targetHeight = when {
|
||||||
|
parentHeight == 0 -> desiredHeight
|
||||||
|
shouldShowFullScreen || parentHeight != initialParentHeight -> parentHeight
|
||||||
|
else -> min(parentHeight, desiredHeight)
|
||||||
|
}
|
||||||
|
|
||||||
if (view.height != targetHeight) {
|
if (view.height != targetHeight) {
|
||||||
view.updateLayoutParams {
|
view.updateLayoutParams {
|
||||||
|
@ -126,6 +138,11 @@ class StoryViewsAndRepliesDialogFragment : FixedRoundedCornerBottomSheetDialogFr
|
||||||
storyViewerPageViewModel.startDirectReply(storyId, recipientId)
|
storyViewerPageViewModel.startDirectReply(storyId, recipientId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun requestFullScreen(fullscreen: Boolean) {
|
||||||
|
shouldShowFullScreen = fullscreen
|
||||||
|
requireView().invalidate()
|
||||||
|
}
|
||||||
|
|
||||||
private inner class PageChangeCallback : ViewPager2.OnPageChangeCallback() {
|
private inner class PageChangeCallback : ViewPager2.OnPageChangeCallback() {
|
||||||
override fun onPageScrollStateChanged(state: Int) {
|
override fun onPageScrollStateChanged(state: Int) {
|
||||||
if (state == ViewPager2.SCROLL_STATE_IDLE) {
|
if (state == ViewPager2.SCROLL_STATE_IDLE) {
|
||||||
|
|
Ładowanie…
Reference in New Issue