Fix multiple issues in CFv2.

This commit is contained in:
Cody Henthorne 2023-07-17 12:15:14 -04:00 committed by Nicholas Tinsley
parent 6be9225fbd
commit 3db83c1602
4 changed files with 105 additions and 17 deletions

View file

@ -1,40 +1,101 @@
package org.thoughtcrime.securesms.conversation.v2 package org.thoughtcrime.securesms.conversation.v2
import android.content.Intent import android.content.Intent
import android.os.Bundle
import android.view.MotionEvent import android.view.MotionEvent
import android.view.Window
import androidx.activity.viewModels import androidx.activity.viewModels
import androidx.fragment.app.Fragment import io.reactivex.rxjava3.subjects.PublishSubject
import org.thoughtcrime.securesms.components.FragmentWrapperActivity import io.reactivex.rxjava3.subjects.Subject
import org.thoughtcrime.securesms.PassphraseRequiredActivity
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.app.subscription.DonationPaymentComponent
import org.thoughtcrime.securesms.components.settings.app.subscription.StripeRepository
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaController import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaController
import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaControllerOwner import org.thoughtcrime.securesms.components.voice.VoiceNoteMediaControllerOwner
import org.thoughtcrime.securesms.util.Debouncer
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme
import java.util.concurrent.TimeUnit
/** /**
* Wrapper activity for ConversationFragment. * Wrapper activity for ConversationFragment.
*/ */
class ConversationActivity : FragmentWrapperActivity(), VoiceNoteMediaControllerOwner { class ConversationActivity : PassphraseRequiredActivity(), VoiceNoteMediaControllerOwner, DonationPaymentComponent {
companion object {
private const val STATE_WATERMARK = "share_data_watermark"
}
private val theme = DynamicNoActionBarTheme() private val theme = DynamicNoActionBarTheme()
private val transitionDebouncer: Debouncer = Debouncer(150, TimeUnit.MILLISECONDS)
private var shareDataTimestamp: Long = -1L
override val voiceNoteMediaController = VoiceNoteMediaController(this, true) override val voiceNoteMediaController = VoiceNoteMediaController(this, true)
override val stripeRepository: StripeRepository by lazy { StripeRepository(this) }
override val googlePayResultPublisher: Subject<DonationPaymentComponent.GooglePayResult> = PublishSubject.create()
private val motionEventRelay: MotionEventRelay by viewModels() private val motionEventRelay: MotionEventRelay by viewModels()
override fun onPreCreate() { override fun onPreCreate() {
theme.onCreate(this) theme.onCreate(this)
} }
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
supportPostponeEnterTransition()
transitionDebouncer.publish { supportStartPostponedEnterTransition() }
window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
if (savedInstanceState != null) {
shareDataTimestamp = savedInstanceState.getLong(STATE_WATERMARK, -1L)
} else if (intent.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY != 0) {
shareDataTimestamp = System.currentTimeMillis()
}
setContentView(R.layout.fragment_container)
if (savedInstanceState == null) {
replaceFragment()
}
}
override fun onResume() { override fun onResume() {
super.onResume() super.onResume()
theme.onResume(this) theme.onResume(this)
} }
override fun getFragment(): Fragment = ConversationFragment().apply { override fun onSaveInstanceState(outState: Bundle) {
arguments = intent.extras super.onSaveInstanceState(outState)
outState.putLong(STATE_WATERMARK, shareDataTimestamp)
}
override fun onDestroy() {
super.onDestroy()
transitionDebouncer.clear()
} }
override fun onNewIntent(intent: Intent?) { override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent) super.onNewIntent(intent)
error("ON NEW INTENT") setIntent(intent)
replaceFragment()
}
@Suppress("DEPRECATION")
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
googlePayResultPublisher.onNext(DonationPaymentComponent.GooglePayResult(requestCode, resultCode, data))
}
private fun replaceFragment() {
val fragment = ConversationFragment().apply {
arguments = intent.extras
}
supportFragmentManager
.beginTransaction()
.replace(R.id.fragment_container, fragment)
.disallowAddToBackStack()
.commitNowAllowingStateLoss()
} }
override fun dispatchTouchEvent(ev: MotionEvent?): Boolean { override fun dispatchTouchEvent(ev: MotionEvent?): Boolean {

View file

@ -227,7 +227,6 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModelV2
import org.thoughtcrime.securesms.longmessage.LongMessageFragment import org.thoughtcrime.securesms.longmessage.LongMessageFragment
import org.thoughtcrime.securesms.mediaoverview.MediaOverviewActivity import org.thoughtcrime.securesms.mediaoverview.MediaOverviewActivity
import org.thoughtcrime.securesms.mediapreview.MediaIntentFactory import org.thoughtcrime.securesms.mediapreview.MediaIntentFactory
import org.thoughtcrime.securesms.mediapreview.MediaIntentFactory.create
import org.thoughtcrime.securesms.mediapreview.MediaPreviewV2Activity import org.thoughtcrime.securesms.mediapreview.MediaPreviewV2Activity
import org.thoughtcrime.securesms.mediasend.Media import org.thoughtcrime.securesms.mediasend.Media
import org.thoughtcrime.securesms.mediasend.MediaSendActivityResult import org.thoughtcrime.securesms.mediasend.MediaSendActivityResult
@ -436,6 +435,7 @@ class ConversationFragment :
private lateinit var conversationItemDecorations: ConversationItemDecorations private lateinit var conversationItemDecorations: ConversationItemDecorations
private lateinit var optionsMenuCallback: ConversationOptionsMenuCallback private lateinit var optionsMenuCallback: ConversationOptionsMenuCallback
private lateinit var typingIndicatorDecoration: TypingIndicatorDecoration private lateinit var typingIndicatorDecoration: TypingIndicatorDecoration
private lateinit var backPressedCallback: BackPressedDelegate
private var animationsAllowed = false private var animationsAllowed = false
private var actionMode: ActionMode? = null private var actionMode: ActionMode? = null
@ -773,6 +773,11 @@ class ConversationFragment :
private fun doAfterFirstRender() { private fun doAfterFirstRender() {
Log.d(TAG, "doAfterFirstRender") Log.d(TAG, "doAfterFirstRender")
activity?.supportStartPostponedEnterTransition()
backPressedCallback = BackPressedDelegate()
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner, backPressedCallback)
attachmentManager = AttachmentManager(requireContext(), requireView(), AttachmentManagerListener()) attachmentManager = AttachmentManager(requireContext(), requireView(), AttachmentManagerListener())
EventBus.getDefault().registerForLifecycle(groupCallViewModel, viewLifecycleOwner) EventBus.getDefault().registerForLifecycle(groupCallViewModel, viewLifecycleOwner)
@ -900,6 +905,7 @@ class ConversationFragment :
disposables.add( disposables.add(
draftViewModel draftViewModel
.state .state
.distinctUntilChanged { previous, next -> previous.voiceNoteDraft == next.voiceNoteDraft }
.subscribe { .subscribe {
inputPanel.voiceNoteDraft = it.voiceNoteDraft inputPanel.voiceNoteDraft = it.voiceNoteDraft
updateToggleButtonState() updateToggleButtonState()
@ -1897,6 +1903,21 @@ class ConversationFragment :
composeText.clearFocus() composeText.clearFocus()
} }
private inner class BackPressedDelegate : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
Log.d(TAG, "onBackPressed()")
if (reactionDelegate.isShowing) {
reactionDelegate.hide()
} else if (isSearchRequested) {
searchMenuItem?.collapseActionView()
} else if (args.conversationScreenType.isInBubble) {
requireActivity().onBackPressed()
} else {
requireActivity().finish()
}
}
}
//region Message action handling //region Message action handling
private fun handleReplyToMessage(conversationMessage: ConversationMessage) { private fun handleReplyToMessage(conversationMessage: ConversationMessage) {
@ -2490,7 +2511,13 @@ class ConversationFragment :
override fun goToMediaPreview(parent: ConversationItem, sharedElement: View, args: MediaIntentFactory.MediaPreviewArgs) { override fun goToMediaPreview(parent: ConversationItem, sharedElement: View, args: MediaIntentFactory.MediaPreviewArgs) {
if (this@ConversationFragment.args.conversationScreenType.isInBubble) { if (this@ConversationFragment.args.conversationScreenType.isInBubble) {
requireActivity().startActivity(create(requireActivity(), args.skipSharedElementTransition(true))) val recipient = viewModel.recipientSnapshot ?: return
val intent = ConversationIntents.createBuilderSync(requireActivity(), recipient.id, viewModel.threadId)
.withStartingPosition(binding.conversationItemRecycler.getChildAdapterPosition(parent))
.build()
requireActivity().startActivity(intent)
requireActivity().startActivity(MediaIntentFactory.create(requireActivity(), args.skipSharedElementTransition(true)))
return return
} }
@ -2506,7 +2533,7 @@ class ConversationFragment :
sharedElement.transitionName = MediaPreviewV2Activity.SHARED_ELEMENT_TRANSITION_NAME sharedElement.transitionName = MediaPreviewV2Activity.SHARED_ELEMENT_TRANSITION_NAME
requireActivity().setExitSharedElementCallback(MaterialContainerTransformSharedElementCallback()) requireActivity().setExitSharedElementCallback(MaterialContainerTransformSharedElementCallback())
val options = ActivityOptions.makeSceneTransitionAnimation(requireActivity(), sharedElement, MediaPreviewV2Activity.SHARED_ELEMENT_TRANSITION_NAME) val options = ActivityOptions.makeSceneTransitionAnimation(requireActivity(), sharedElement, MediaPreviewV2Activity.SHARED_ELEMENT_TRANSITION_NAME)
requireActivity().startActivity(create(requireActivity(), args), options.toBundle()) requireActivity().startActivity(MediaIntentFactory.create(requireActivity(), args), options.toBundle())
} }
override fun onEditedIndicatorClicked(messageRecord: MessageRecord) { override fun onEditedIndicatorClicked(messageRecord: MessageRecord) {
@ -2655,13 +2682,13 @@ class ConversationFragment :
} }
} }
) )
} else {
clearFocusedItem()
adapter.toggleSelection(item)
binding.conversationItemRecycler.invalidateItemDecorations()
actionMode = (requireActivity() as AppCompatActivity).startSupportActionMode(actionModeCallback)
} }
} else {
clearFocusedItem()
adapter.toggleSelection(item)
binding.conversationItemRecycler.invalidateItemDecorations()
actionMode = (requireActivity() as AppCompatActivity).startSupportActionMode(actionModeCallback)
} }
} }

View file

@ -207,7 +207,7 @@ class ConversationRepository(
identityRecordsState: IdentityRecordsState? identityRecordsState: IdentityRecordsState?
): Completable { ): Completable {
val sendCompletable = Completable.create { emitter -> val sendCompletable = Completable.create { emitter ->
if (body.isEmpty() && slideDeck?.containsMediaSlide() != true && preUploadResults.isEmpty()) { if (body.isEmpty() && slideDeck?.containsMediaSlide() != true && preUploadResults.isEmpty() && contacts.isEmpty()) {
emitter.onError(InvalidMessageException("Message is empty!")) emitter.onError(InvalidMessageException("Message is empty!"))
return@create return@create
} }

View file

@ -71,7 +71,7 @@ import kotlin.time.Duration
* ConversationViewModel, which operates solely off of a thread id that never changes. * ConversationViewModel, which operates solely off of a thread id that never changes.
*/ */
class ConversationViewModel( class ConversationViewModel(
private val threadId: Long, val threadId: Long,
requestedStartingPosition: Int, requestedStartingPosition: Int,
private val repository: ConversationRepository, private val repository: ConversationRepository,
recipientRepository: ConversationRecipientRepository, recipientRepository: ConversationRecipientRepository,