kopia lustrzana https://github.com/ryukoposting/Signal-Android
Safety number check and profile refresh for group sends.
rodzic
14849d6e45
commit
76a9342afa
|
@ -11,17 +11,25 @@ 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 io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
import io.reactivex.rxjava3.kotlin.subscribeBy
|
||||||
|
import org.signal.core.util.concurrent.SignalExecutors
|
||||||
|
import org.signal.core.util.logging.Log
|
||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
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
|
||||||
import org.thoughtcrime.securesms.components.settings.configure
|
import org.thoughtcrime.securesms.components.settings.configure
|
||||||
import org.thoughtcrime.securesms.conversation.colors.Colorizer
|
import org.thoughtcrime.securesms.conversation.colors.Colorizer
|
||||||
|
import org.thoughtcrime.securesms.conversation.ui.error.SafetyNumberChangeDialog
|
||||||
import org.thoughtcrime.securesms.conversation.ui.mentions.MentionsPickerFragment
|
import org.thoughtcrime.securesms.conversation.ui.mentions.MentionsPickerFragment
|
||||||
import org.thoughtcrime.securesms.conversation.ui.mentions.MentionsPickerViewModel
|
import org.thoughtcrime.securesms.conversation.ui.mentions.MentionsPickerViewModel
|
||||||
|
import org.thoughtcrime.securesms.database.model.Mention
|
||||||
|
import org.thoughtcrime.securesms.jobs.RetrieveProfileJob
|
||||||
import org.thoughtcrime.securesms.keyboard.KeyboardPage
|
import org.thoughtcrime.securesms.keyboard.KeyboardPage
|
||||||
import org.thoughtcrime.securesms.keyboard.KeyboardPagerViewModel
|
import org.thoughtcrime.securesms.keyboard.KeyboardPagerViewModel
|
||||||
import org.thoughtcrime.securesms.keyboard.emoji.EmojiKeyboardCallback
|
import org.thoughtcrime.securesms.keyboard.emoji.EmojiKeyboardCallback
|
||||||
|
import org.thoughtcrime.securesms.mediasend.v2.UntrustedRecords
|
||||||
import org.thoughtcrime.securesms.reactions.any.ReactWithAnyEmojiBottomSheetDialogFragment
|
import org.thoughtcrime.securesms.reactions.any.ReactWithAnyEmojiBottomSheetDialogFragment
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||||
|
@ -51,7 +59,8 @@ class StoryGroupReplyFragment :
|
||||||
BottomSheetBehaviorDelegate,
|
BottomSheetBehaviorDelegate,
|
||||||
StoryReplyComposer.Callback,
|
StoryReplyComposer.Callback,
|
||||||
EmojiKeyboardCallback,
|
EmojiKeyboardCallback,
|
||||||
ReactWithAnyEmojiBottomSheetDialogFragment.Callback {
|
ReactWithAnyEmojiBottomSheetDialogFragment.Callback,
|
||||||
|
SafetyNumberChangeDialog.Callback {
|
||||||
|
|
||||||
private val viewModel: StoryGroupReplyViewModel by viewModels(
|
private val viewModel: StoryGroupReplyViewModel by viewModels(
|
||||||
factoryProducer = {
|
factoryProducer = {
|
||||||
|
@ -81,6 +90,10 @@ class StoryGroupReplyFragment :
|
||||||
private lateinit var composer: StoryReplyComposer
|
private lateinit var composer: StoryReplyComposer
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
|
SignalExecutors.BOUNDED.execute {
|
||||||
|
RetrieveProfileJob.enqueue(groupRecipientId)
|
||||||
|
}
|
||||||
|
|
||||||
recyclerView = view.findViewById(R.id.recycler)
|
recyclerView = view.findViewById(R.id.recycler)
|
||||||
composer = view.findViewById(R.id.composer)
|
composer = view.findViewById(R.id.composer)
|
||||||
|
|
||||||
|
@ -194,9 +207,12 @@ class StoryGroupReplyFragment :
|
||||||
recyclerView.isNestedScrollingEnabled = child == StoryViewsAndRepliesPagerParent.Child.REPLIES
|
recyclerView.isNestedScrollingEnabled = child == StoryViewsAndRepliesPagerParent.Child.REPLIES
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var resendBody: CharSequence? = null
|
||||||
|
private var resendMentions: List<Mention> = emptyList()
|
||||||
|
|
||||||
override fun onSendActionClicked() {
|
override fun onSendActionClicked() {
|
||||||
val (body, mentions) = composer.consumeInput()
|
val (body, mentions) = composer.consumeInput()
|
||||||
lifecycleDisposable += StoryGroupReplySender.sendReply(requireContext(), storyId, body, mentions).subscribe()
|
performSend(body, mentions)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPickReactionClicked() {
|
override fun onPickReactionClicked() {
|
||||||
|
@ -299,6 +315,8 @@ class StoryGroupReplyFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private val TAG = Log.tag(StoryGroupReplyFragment::class.java)
|
||||||
|
|
||||||
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"
|
||||||
|
|
||||||
|
@ -312,6 +330,43 @@ class StoryGroupReplyFragment :
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun performSend(body: CharSequence, mentions: List<Mention>) {
|
||||||
|
lifecycleDisposable += StoryGroupReplySender.sendReply(requireContext(), storyId, body, mentions)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribeBy(
|
||||||
|
onError = {
|
||||||
|
if (it is UntrustedRecords.UntrustedRecordsException) {
|
||||||
|
resendBody = body
|
||||||
|
resendMentions = mentions
|
||||||
|
|
||||||
|
SafetyNumberChangeDialog.show(childFragmentManager, it.untrustedRecords)
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Failed to send reply", it)
|
||||||
|
val context = context
|
||||||
|
if (context != null) {
|
||||||
|
Toast.makeText(context, R.string.message_details_recipient__failed_to_send, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onSendAnywayAfterSafetyNumberChange(changedRecipients: MutableList<RecipientId>) {
|
||||||
|
val resendBody = resendBody
|
||||||
|
if (resendBody != null) {
|
||||||
|
performSend(resendBody, resendMentions)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMessageResentAfterSafetyNumberChange() {
|
||||||
|
error("Should never get here.")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onCanceled() {
|
||||||
|
resendBody = null
|
||||||
|
resendMentions = emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
interface Callback {
|
interface Callback {
|
||||||
fun onStartDirectReply(recipientId: RecipientId)
|
fun onStartDirectReply(recipientId: RecipientId)
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,14 @@ package org.thoughtcrime.securesms.stories.viewer.reply.group
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import io.reactivex.rxjava3.core.Completable
|
import io.reactivex.rxjava3.core.Completable
|
||||||
|
import io.reactivex.rxjava3.core.Single
|
||||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||||
|
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
|
||||||
import org.thoughtcrime.securesms.database.SignalDatabase
|
import org.thoughtcrime.securesms.database.SignalDatabase
|
||||||
import org.thoughtcrime.securesms.database.model.Mention
|
import org.thoughtcrime.securesms.database.model.Mention
|
||||||
import org.thoughtcrime.securesms.database.model.ParentStoryId
|
import org.thoughtcrime.securesms.database.model.ParentStoryId
|
||||||
import org.thoughtcrime.securesms.database.model.StoryType
|
import org.thoughtcrime.securesms.database.model.StoryType
|
||||||
|
import org.thoughtcrime.securesms.mediasend.v2.UntrustedRecords
|
||||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
|
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
|
||||||
import org.thoughtcrime.securesms.sms.MessageSender
|
import org.thoughtcrime.securesms.sms.MessageSender
|
||||||
|
|
||||||
|
@ -24,38 +27,47 @@ object StoryGroupReplySender {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendInternal(context: Context, storyId: Long, body: CharSequence, mentions: List<Mention>, isReaction: Boolean): Completable {
|
private fun sendInternal(context: Context, storyId: Long, body: CharSequence, mentions: List<Mention>, isReaction: Boolean): Completable {
|
||||||
return Completable.create {
|
val messageAndRecipient = Single.fromCallable {
|
||||||
|
|
||||||
val message = SignalDatabase.mms.getMessageRecord(storyId)
|
val message = SignalDatabase.mms.getMessageRecord(storyId)
|
||||||
val recipient = SignalDatabase.threads.getRecipientForThreadId(message.threadId)!!
|
val recipient = SignalDatabase.threads.getRecipientForThreadId(message.threadId)!!
|
||||||
|
|
||||||
MessageSender.send(
|
message to recipient
|
||||||
context,
|
}
|
||||||
OutgoingMediaMessage(
|
|
||||||
recipient,
|
return messageAndRecipient.flatMapCompletable { (message, recipient) ->
|
||||||
body.toString(),
|
UntrustedRecords.checkForBadIdentityRecords(setOf(ContactSearchKey.KnownRecipient(recipient.id)))
|
||||||
emptyList(),
|
.andThen(
|
||||||
System.currentTimeMillis(),
|
Completable.create {
|
||||||
0,
|
|
||||||
0L,
|
MessageSender.send(
|
||||||
false,
|
context,
|
||||||
0,
|
OutgoingMediaMessage(
|
||||||
StoryType.NONE,
|
recipient,
|
||||||
ParentStoryId.GroupReply(message.id),
|
body.toString(),
|
||||||
isReaction,
|
emptyList(),
|
||||||
null,
|
System.currentTimeMillis(),
|
||||||
emptyList(),
|
0,
|
||||||
emptyList(),
|
0L,
|
||||||
mentions,
|
false,
|
||||||
emptySet(),
|
0,
|
||||||
emptySet()
|
StoryType.NONE,
|
||||||
),
|
ParentStoryId.GroupReply(message.id),
|
||||||
message.threadId,
|
isReaction,
|
||||||
false,
|
null,
|
||||||
null
|
emptyList(),
|
||||||
) {
|
emptyList(),
|
||||||
it.onComplete()
|
mentions,
|
||||||
}
|
emptySet(),
|
||||||
|
emptySet()
|
||||||
|
),
|
||||||
|
message.threadId,
|
||||||
|
false,
|
||||||
|
null
|
||||||
|
) {
|
||||||
|
it.onComplete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
}.subscribeOn(Schedulers.io())
|
}.subscribeOn(Schedulers.io())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Ładowanie…
Reference in New Issue