mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-02-23 03:05:26 +00:00
Add animation when you directly react to a story.
This commit is contained in:
committed by
Greyson Parrelli
parent
c0f843061e
commit
cdef21d6c0
@@ -18,6 +18,7 @@ import androidx.core.view.GestureDetectorCompat
|
||||
import androidx.core.view.doOnNextLayout
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.setFragmentResultListener
|
||||
import androidx.fragment.app.viewModels
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.rxjava3.core.Observable
|
||||
@@ -45,6 +46,7 @@ import org.thoughtcrime.securesms.stories.dialogs.StoryContextMenu
|
||||
import org.thoughtcrime.securesms.stories.viewer.StoryViewerViewModel
|
||||
import org.thoughtcrime.securesms.stories.viewer.reply.direct.StoryDirectReplyDialogFragment
|
||||
import org.thoughtcrime.securesms.stories.viewer.reply.group.StoryGroupReplyBottomSheetDialogFragment
|
||||
import org.thoughtcrime.securesms.stories.viewer.reply.reaction.OnReactionSentView
|
||||
import org.thoughtcrime.securesms.stories.viewer.reply.tabs.StoryViewsAndRepliesDialogFragment
|
||||
import org.thoughtcrime.securesms.stories.viewer.text.StoryTextPostPreviewFragment
|
||||
import org.thoughtcrime.securesms.stories.viewer.views.StoryViewsBottomSheetDialogFragment
|
||||
@@ -113,6 +115,7 @@ class StoryViewerPageFragment :
|
||||
val caption: TextView = view.findViewById(R.id.story_caption)
|
||||
val largeCaption: TextView = view.findViewById(R.id.story_large_caption)
|
||||
val largeCaptionOverlay: View = view.findViewById(R.id.story_large_caption_overlay)
|
||||
val reactionAnimationView: OnReactionSentView = view.findViewById(R.id.on_reaction_sent_view)
|
||||
|
||||
storySlate = view.findViewById(R.id.story_slate)
|
||||
progressBar = view.findViewById(R.id.progress)
|
||||
@@ -204,6 +207,12 @@ class StoryViewerPageFragment :
|
||||
}
|
||||
}
|
||||
|
||||
reactionAnimationView.callback = object : OnReactionSentView.Callback {
|
||||
override fun onFinished() {
|
||||
viewModel.setIsDisplayingReactionAnimation(false)
|
||||
}
|
||||
}
|
||||
|
||||
sharedViewModel.isScrolling.observe(viewLifecycleOwner) { isScrolling ->
|
||||
viewModel.setIsUserScrollingParent(isScrolling)
|
||||
}
|
||||
@@ -276,6 +285,14 @@ class StoryViewerPageFragment :
|
||||
}
|
||||
|
||||
adjustConstraintsForScreenDimensions(viewsAndReplies, cardWrapper, card)
|
||||
|
||||
childFragmentManager.setFragmentResultListener(StoryDirectReplyDialogFragment.REQUEST_EMOJI, viewLifecycleOwner) { _, bundle ->
|
||||
val emoji = bundle.getString(StoryDirectReplyDialogFragment.REQUEST_EMOJI)
|
||||
if (emoji != null) {
|
||||
reactionAnimationView.playForEmoji(emoji)
|
||||
viewModel.setIsDisplayingReactionAnimation(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
||||
@@ -135,6 +135,10 @@ class StoryViewerPageViewModel(
|
||||
storyViewerPlaybackStore.update { it.copy(isSelectedPage = isSelectedPage) }
|
||||
}
|
||||
|
||||
fun setIsDisplayingReactionAnimation(isDisplayingReactionAnimation: Boolean) {
|
||||
storyViewerPlaybackStore.update { it.copy(isDisplayingReactionAnimation = isDisplayingReactionAnimation) }
|
||||
}
|
||||
|
||||
fun setIsDisplayingContextMenu(isDisplayingContextMenu: Boolean) {
|
||||
storyViewerPlaybackStore.update { it.copy(isDisplayingContextMenu = isDisplayingContextMenu) }
|
||||
}
|
||||
|
||||
@@ -13,7 +13,8 @@ data class StoryViewerPlaybackState(
|
||||
val isSelectedPage: Boolean = false,
|
||||
val isDisplayingSlate: Boolean = false,
|
||||
val isFragmentResumed: Boolean = false,
|
||||
val isDisplayingLinkPreviewTooltip: Boolean = false
|
||||
val isDisplayingLinkPreviewTooltip: Boolean = false,
|
||||
val isDisplayingReactionAnimation: Boolean = false
|
||||
) {
|
||||
val isPaused: Boolean = !areSegmentsInitialized ||
|
||||
isUserTouching ||
|
||||
@@ -28,5 +29,6 @@ data class StoryViewerPlaybackState(
|
||||
!isSelectedPage ||
|
||||
isDisplayingSlate ||
|
||||
!isFragmentResumed ||
|
||||
isDisplayingLinkPreviewTooltip
|
||||
isDisplayingLinkPreviewTooltip ||
|
||||
isDisplayingReactionAnimation
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import android.view.KeyEvent
|
||||
import android.view.View
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.fragment.app.setFragmentResult
|
||||
import androidx.fragment.app.viewModels
|
||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import org.thoughtcrime.securesms.R
|
||||
@@ -146,6 +147,7 @@ class StoryDirectReplyDialogFragment :
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val REQUEST_EMOJI = "request.code.emoji"
|
||||
|
||||
private const val ARG_STORY_ID = "arg.story.id"
|
||||
private const val ARG_RECIPIENT_ID = "arg.recipient.id"
|
||||
@@ -180,7 +182,12 @@ class StoryDirectReplyDialogFragment :
|
||||
lifecycleDisposable += viewModel.sendReaction(emoji)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe {
|
||||
// TODO [alex] -- Reaction explosion animation instead of toast.
|
||||
setFragmentResult(
|
||||
REQUEST_EMOJI,
|
||||
Bundle().apply {
|
||||
putString(REQUEST_EMOJI, emoji)
|
||||
}
|
||||
)
|
||||
Toast.makeText(requireContext(), R.string.StoryDirectReplyDialogFragment__reaction_sent, Toast.LENGTH_LONG).show()
|
||||
dismissAllowingStateLoss()
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
package org.thoughtcrime.securesms.stories.viewer.reply.reaction
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import android.widget.FrameLayout
|
||||
import androidx.constraintlayout.motion.widget.MotionLayout
|
||||
import androidx.constraintlayout.motion.widget.TransitionAdapter
|
||||
import androidx.core.view.doOnNextLayout
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiImageView
|
||||
import org.thoughtcrime.securesms.util.visible
|
||||
|
||||
class OnReactionSentView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null
|
||||
) : FrameLayout(context, attrs) {
|
||||
|
||||
var callback: Callback? = null
|
||||
|
||||
init {
|
||||
inflate(context, R.layout.on_reaction_sent_view, this)
|
||||
}
|
||||
|
||||
private val motionLayout: MotionLayout = findViewById(R.id.motion_layout)
|
||||
|
||||
init {
|
||||
motionLayout.addTransitionListener(object : TransitionAdapter() {
|
||||
override fun onTransitionCompleted(p0: MotionLayout?, p1: Int) {
|
||||
visible = false
|
||||
callback?.onFinished()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fun playForEmoji(emoji: CharSequence) {
|
||||
motionLayout.progress = 0f
|
||||
motionLayout.visible = true
|
||||
|
||||
listOf(
|
||||
R.id.emoji_1,
|
||||
R.id.emoji_2,
|
||||
R.id.emoji_3,
|
||||
R.id.emoji_4,
|
||||
R.id.emoji_5,
|
||||
R.id.emoji_6,
|
||||
R.id.emoji_7,
|
||||
R.id.emoji_8,
|
||||
R.id.emoji_9,
|
||||
R.id.emoji_10,
|
||||
R.id.emoji_11,
|
||||
).forEach {
|
||||
findViewById<EmojiImageView>(it).setImageEmoji(emoji)
|
||||
}
|
||||
|
||||
motionLayout.requestLayout()
|
||||
motionLayout.doOnNextLayout {
|
||||
motionLayout.transitionToEnd()
|
||||
}
|
||||
}
|
||||
|
||||
interface Callback {
|
||||
fun onFinished()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user