Add share highwater timestamp protection to CFv2.
This commit is contained in:
parent
e6c9449e3c
commit
67d4f666ce
5 changed files with 40 additions and 10 deletions
|
@ -62,8 +62,8 @@ class DraftRepository(
|
|||
val TAG = Log.tag(DraftRepository::class.java)
|
||||
}
|
||||
|
||||
fun getShareOrDraftData(): Maybe<Pair<ShareOrDraftData?, Drafts?>> {
|
||||
return MaybeCompat.fromCallable { getShareOrDraftDataInternal() }
|
||||
fun getShareOrDraftData(lastShareDataTimestamp: Long): Maybe<Pair<ShareOrDraftData?, Drafts?>> {
|
||||
return MaybeCompat.fromCallable { getShareOrDraftDataInternal(lastShareDataTimestamp) }
|
||||
.observeOn(Schedulers.io())
|
||||
}
|
||||
|
||||
|
@ -73,7 +73,17 @@ class DraftRepository(
|
|||
*
|
||||
* Note: Voice note drafts are handled differently and via the [DraftViewModel.state]
|
||||
*/
|
||||
private fun getShareOrDraftDataInternal(): Pair<ShareOrDraftData?, Drafts?>? {
|
||||
@Suppress("ConvertTwoComparisonsToRangeCheck")
|
||||
private fun getShareOrDraftDataInternal(lastShareDataTimestamp: Long): Pair<ShareOrDraftData?, Drafts?>? {
|
||||
val sharedDataTimestamp: Long = conversationArguments?.shareDataTimestamp ?: -1
|
||||
Log.d(TAG, "Shared this data at $sharedDataTimestamp and last processed share data at $lastShareDataTimestamp")
|
||||
if (sharedDataTimestamp > 0 && sharedDataTimestamp <= lastShareDataTimestamp) {
|
||||
Log.d(TAG, "Already processed this share data. Skipping.")
|
||||
return null
|
||||
} else {
|
||||
Log.d(TAG, "Have not processed this share data. Proceeding.")
|
||||
}
|
||||
|
||||
val shareText = conversationArguments?.draftText
|
||||
val shareMedia = conversationArguments?.draftMedia
|
||||
val shareContentType = conversationArguments?.draftContentType
|
||||
|
|
|
@ -168,8 +168,8 @@ class DraftViewModel @JvmOverloads constructor(
|
|||
.observeOn(AndroidSchedulers.mainThread())
|
||||
}
|
||||
|
||||
fun loadShareOrDraftData(): Maybe<DraftRepository.ShareOrDraftData> {
|
||||
return repository.getShareOrDraftData()
|
||||
fun loadShareOrDraftData(lastShareDataTimestamp: Long): Maybe<DraftRepository.ShareOrDraftData> {
|
||||
return repository.getShareOrDraftData(lastShareDataTimestamp)
|
||||
.doOnSuccess { (_, drafts) ->
|
||||
if (drafts != null) {
|
||||
store.update { saveDrafts(it.copyAndSetDrafts(drafts = drafts)) }
|
||||
|
|
|
@ -28,7 +28,6 @@ class ConversationActivity : PassphraseRequiredActivity(), VoiceNoteMediaControl
|
|||
|
||||
private val theme = DynamicNoActionBarTheme()
|
||||
private val transitionDebouncer: Debouncer = Debouncer(150, TimeUnit.MILLISECONDS)
|
||||
private var shareDataTimestamp: Long = -1L
|
||||
|
||||
override val voiceNoteMediaController = VoiceNoteMediaController(this, true)
|
||||
|
||||
|
@ -36,6 +35,7 @@ class ConversationActivity : PassphraseRequiredActivity(), VoiceNoteMediaControl
|
|||
override val googlePayResultPublisher: Subject<DonationPaymentComponent.GooglePayResult> = PublishSubject.create()
|
||||
|
||||
private val motionEventRelay: MotionEventRelay by viewModels()
|
||||
private val shareDataTimestampViewModel: ShareDataTimestampViewModel by viewModels()
|
||||
|
||||
override fun onPreCreate() {
|
||||
theme.onCreate(this)
|
||||
|
@ -47,9 +47,9 @@ class ConversationActivity : PassphraseRequiredActivity(), VoiceNoteMediaControl
|
|||
window.requestFeature(Window.FEATURE_ACTIVITY_TRANSITIONS)
|
||||
|
||||
if (savedInstanceState != null) {
|
||||
shareDataTimestamp = savedInstanceState.getLong(STATE_WATERMARK, -1L)
|
||||
shareDataTimestampViewModel.timestamp = savedInstanceState.getLong(STATE_WATERMARK, -1L)
|
||||
} else if (intent.flags and Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY != 0) {
|
||||
shareDataTimestamp = System.currentTimeMillis()
|
||||
shareDataTimestampViewModel.timestamp = System.currentTimeMillis()
|
||||
}
|
||||
|
||||
setContentView(R.layout.fragment_container)
|
||||
|
@ -66,7 +66,7 @@ class ConversationActivity : PassphraseRequiredActivity(), VoiceNoteMediaControl
|
|||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
super.onSaveInstanceState(outState)
|
||||
outState.putLong(STATE_WATERMARK, shareDataTimestamp)
|
||||
outState.putLong(STATE_WATERMARK, shareDataTimestampViewModel.timestamp)
|
||||
}
|
||||
|
||||
override fun onDestroy() {
|
||||
|
|
|
@ -407,6 +407,8 @@ class ConversationFragment :
|
|||
InlineQueryViewModelV2(recipientRepository = conversationRecipientRepository)
|
||||
}
|
||||
|
||||
private val shareDataTimestampViewModel: ShareDataTimestampViewModel by activityViewModels()
|
||||
|
||||
private val inlineQueryController: InlineQueryResultsControllerV2 by lazy {
|
||||
InlineQueryResultsControllerV2(
|
||||
this,
|
||||
|
@ -907,7 +909,7 @@ class ConversationFragment :
|
|||
this::handleReplyToMessage
|
||||
).attachToRecyclerView(binding.conversationItemRecycler)
|
||||
|
||||
draftViewModel.loadShareOrDraftData()
|
||||
draftViewModel.loadShareOrDraftData(shareDataTimestampViewModel.timestamp)
|
||||
.subscribeBy { data -> handleShareOrDraftData(data) }
|
||||
.addTo(disposables)
|
||||
|
||||
|
@ -1298,6 +1300,8 @@ class ConversationFragment :
|
|||
}
|
||||
|
||||
private fun handleShareOrDraftData(data: ShareOrDraftData) {
|
||||
shareDataTimestampViewModel.timestamp = args.shareDataTimestamp
|
||||
|
||||
when (data) {
|
||||
is ShareOrDraftData.SendKeyboardImage -> sendMessageWithoutComposeInput(slide = data.slide, clearCompose = false)
|
||||
is ShareOrDraftData.SendSticker -> sendMessageWithoutComposeInput(slide = data.slide, clearCompose = true)
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
/*
|
||||
* Copyright 2023 Signal Messenger, LLC
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
package org.thoughtcrime.securesms.conversation.v2
|
||||
|
||||
import androidx.lifecycle.ViewModel
|
||||
|
||||
/**
|
||||
* Hold the last share timestamp in an activity scoped view model for sharing between
|
||||
* the activity and fragments.
|
||||
*/
|
||||
class ShareDataTimestampViewModel : ViewModel() {
|
||||
var timestamp: Long = -1L
|
||||
}
|
Loading…
Add table
Reference in a new issue