kopia lustrzana https://github.com/ryukoposting/Signal-Android
Add story send multi-send, error, and improved SNC states.
rodzic
7f2f5a182f
commit
2f0f26c328
|
@ -23,6 +23,7 @@ import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import com.annimon.stream.Stream;
|
import com.annimon.stream.Stream;
|
||||||
|
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||||
|
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.R;
|
import org.thoughtcrime.securesms.R;
|
||||||
|
@ -165,7 +166,7 @@ public final class SafetyNumberChangeDialog extends DialogFragment implements Sa
|
||||||
|
|
||||||
dialogView = LayoutInflater.from(requireActivity()).inflate(R.layout.safety_number_change_dialog, null);
|
dialogView = LayoutInflater.from(requireActivity()).inflate(R.layout.safety_number_change_dialog, null);
|
||||||
|
|
||||||
AlertDialog.Builder builder = new AlertDialog.Builder(requireActivity(), getTheme());
|
AlertDialog.Builder builder = new MaterialAlertDialogBuilder(requireActivity());
|
||||||
|
|
||||||
configureView(dialogView);
|
configureView(dialogView);
|
||||||
|
|
||||||
|
|
|
@ -1146,6 +1146,7 @@ public class MmsDatabase extends MessageDatabase {
|
||||||
long threadId = getThreadIdForMessage(messageId);
|
long threadId = getThreadIdForMessage(messageId);
|
||||||
updateMailboxBitmask(messageId, Types.BASE_TYPE_MASK, Types.BASE_SENDING_TYPE, Optional.of(threadId));
|
updateMailboxBitmask(messageId, Types.BASE_TYPE_MASK, Types.BASE_SENDING_TYPE, Optional.of(threadId));
|
||||||
ApplicationDependencies.getDatabaseObserver().notifyMessageUpdateObservers(new MessageId(messageId, true));
|
ApplicationDependencies.getDatabaseObserver().notifyMessageUpdateObservers(new MessageId(messageId, true));
|
||||||
|
ApplicationDependencies.getDatabaseObserver().notifyConversationListListeners();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -43,4 +43,12 @@ object StoryDialogs {
|
||||||
|
|
||||||
return shareContacts.any { it is ContactSearchKey.Story && Recipient.resolved(it.recipientId).isMyStory }
|
return shareContacts.any { it is ContactSearchKey.Story && Recipient.resolved(it.recipientId).isMyStory }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun resendStory(context: Context, resend: () -> Unit) {
|
||||||
|
MaterialAlertDialogBuilder(context)
|
||||||
|
.setMessage(R.string.StoryDialogs__story_could_not_be_sent)
|
||||||
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
|
.setPositiveButton(R.string.StoryDialogs__send) { _, _ -> resend() }
|
||||||
|
.show()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,12 +31,14 @@ import org.thoughtcrime.securesms.components.settings.configure
|
||||||
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
||||||
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragment
|
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragment
|
||||||
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragmentArgs
|
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragmentArgs
|
||||||
|
import org.thoughtcrime.securesms.conversation.ui.error.SafetyNumberChangeDialog
|
||||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
|
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
|
||||||
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||||
import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionActivity
|
import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionActivity
|
||||||
import org.thoughtcrime.securesms.permissions.Permissions
|
import org.thoughtcrime.securesms.permissions.Permissions
|
||||||
import org.thoughtcrime.securesms.stories.StoryTextPostModel
|
import org.thoughtcrime.securesms.stories.StoryTextPostModel
|
||||||
import org.thoughtcrime.securesms.stories.dialogs.StoryContextMenu
|
import org.thoughtcrime.securesms.stories.dialogs.StoryContextMenu
|
||||||
|
import org.thoughtcrime.securesms.stories.dialogs.StoryDialogs
|
||||||
import org.thoughtcrime.securesms.stories.my.MyStoriesActivity
|
import org.thoughtcrime.securesms.stories.my.MyStoriesActivity
|
||||||
import org.thoughtcrime.securesms.stories.settings.StorySettingsActivity
|
import org.thoughtcrime.securesms.stories.settings.StorySettingsActivity
|
||||||
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsViewModel
|
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsViewModel
|
||||||
|
@ -178,8 +180,13 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l
|
||||||
if (model.data.storyRecipient.isMyStory) {
|
if (model.data.storyRecipient.isMyStory) {
|
||||||
startActivity(Intent(requireContext(), MyStoriesActivity::class.java))
|
startActivity(Intent(requireContext(), MyStoriesActivity::class.java))
|
||||||
} else if (model.data.primaryStory.messageRecord.isOutgoing && model.data.primaryStory.messageRecord.isFailed) {
|
} else if (model.data.primaryStory.messageRecord.isOutgoing && model.data.primaryStory.messageRecord.isFailed) {
|
||||||
lifecycleDisposable += viewModel.resend(model.data.primaryStory.messageRecord).subscribe()
|
if (model.data.primaryStory.messageRecord.isIdentityMismatchFailure) {
|
||||||
Toast.makeText(requireContext(), R.string.message_recipients_list_item__resend, Toast.LENGTH_SHORT).show()
|
SafetyNumberChangeDialog.show(requireContext(), childFragmentManager, model.data.primaryStory.messageRecord)
|
||||||
|
} else {
|
||||||
|
StoryDialogs.resendStory(requireContext()) {
|
||||||
|
lifecycleDisposable += viewModel.resend(model.data.primaryStory.messageRecord).subscribe()
|
||||||
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(requireActivity(), preview, ViewCompat.getTransitionName(preview) ?: "")
|
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(requireActivity(), preview, ViewCompat.getTransitionName(preview) ?: "")
|
||||||
|
|
||||||
|
|
|
@ -57,6 +57,7 @@ object StoriesLandingItem {
|
||||||
return data.storyRecipient.hasSameContent(newItem.data.storyRecipient) &&
|
return data.storyRecipient.hasSameContent(newItem.data.storyRecipient) &&
|
||||||
data == newItem.data &&
|
data == newItem.data &&
|
||||||
!hasStatusChange(newItem) &&
|
!hasStatusChange(newItem) &&
|
||||||
|
(data.sendingCount == newItem.data.sendingCount && data.failureCount == newItem.data.failureCount) &&
|
||||||
super.areContentsTheSame(newItem)
|
super.areContentsTheSame(newItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -205,12 +206,16 @@ object StoriesLandingItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun presentDateOrStatus(model: Model) {
|
private fun presentDateOrStatus(model: Model) {
|
||||||
if (model.data.primaryStory.messageRecord.isOutgoing && (model.data.primaryStory.messageRecord.isPending || model.data.primaryStory.messageRecord.isMediaPending)) {
|
if (model.data.sendingCount > 0 || (model.data.primaryStory.messageRecord.isOutgoing && (model.data.primaryStory.messageRecord.isPending || model.data.primaryStory.messageRecord.isMediaPending))) {
|
||||||
errorIndicator.visible = false
|
errorIndicator.visible = model.data.failureCount > 0L
|
||||||
date.setText(R.string.StoriesLandingItem__sending)
|
if (model.data.sendingCount > 1) {
|
||||||
} else if (model.data.primaryStory.messageRecord.isOutgoing && model.data.primaryStory.messageRecord.isFailed) {
|
date.text = context.getString(R.string.StoriesLandingItem__sending_d, model.data.sendingCount)
|
||||||
|
} else {
|
||||||
|
date.setText(R.string.StoriesLandingItem__sending)
|
||||||
|
}
|
||||||
|
} else if (model.data.failureCount > 0 || (model.data.primaryStory.messageRecord.isOutgoing && model.data.primaryStory.messageRecord.isFailed)) {
|
||||||
errorIndicator.visible = true
|
errorIndicator.visible = true
|
||||||
date.text = SpanUtil.color(ContextCompat.getColor(context, R.color.signal_alert_primary), context.getString(R.string.StoriesLandingItem__couldnt_send))
|
date.text = SpanUtil.color(ContextCompat.getColor(context, R.color.signal_alert_primary), context.getString(R.string.StoriesLandingItem__send_failed))
|
||||||
} else {
|
} else {
|
||||||
errorIndicator.visible = false
|
errorIndicator.visible = false
|
||||||
date.text = DateUtils.getBriefRelativeTimeSpanString(context, Locale.getDefault(), model.data.dateInMilliseconds)
|
date.text = DateUtils.getBriefRelativeTimeSpanString(context, Locale.getDefault(), model.data.dateInMilliseconds)
|
||||||
|
|
|
@ -16,7 +16,9 @@ data class StoriesLandingItemData(
|
||||||
val secondaryStory: ConversationMessage?,
|
val secondaryStory: ConversationMessage?,
|
||||||
val storyRecipient: Recipient,
|
val storyRecipient: Recipient,
|
||||||
val individualRecipient: Recipient = primaryStory.messageRecord.individualRecipient,
|
val individualRecipient: Recipient = primaryStory.messageRecord.individualRecipient,
|
||||||
val dateInMilliseconds: Long = primaryStory.messageRecord.dateSent
|
val dateInMilliseconds: Long = primaryStory.messageRecord.dateSent,
|
||||||
|
val sendingCount: Long = 0,
|
||||||
|
val failureCount: Long = 0
|
||||||
) : Comparable<StoriesLandingItemData> {
|
) : Comparable<StoriesLandingItemData> {
|
||||||
override fun compareTo(other: StoriesLandingItemData): Int {
|
override fun compareTo(other: StoriesLandingItemData): Int {
|
||||||
return if (storyRecipient.isMyStory && !other.storyRecipient.isMyStory) {
|
return if (storyRecipient.isMyStory && !other.storyRecipient.isMyStory) {
|
||||||
|
|
|
@ -27,6 +27,7 @@ class StoriesLandingRepository(context: Context) {
|
||||||
}.subscribeOn(Schedulers.io())
|
}.subscribeOn(Schedulers.io())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("UsePropertyAccessSyntax")
|
||||||
fun getStories(): Observable<List<StoriesLandingItemData>> {
|
fun getStories(): Observable<List<StoriesLandingItemData>> {
|
||||||
val storyRecipients: Observable<Map<Recipient, List<StoryResult>>> = Observable.create { emitter ->
|
val storyRecipients: Observable<Map<Recipient, List<StoryResult>>> = Observable.create { emitter ->
|
||||||
fun refresh() {
|
fun refresh() {
|
||||||
|
@ -67,7 +68,25 @@ class StoriesLandingRepository(context: Context) {
|
||||||
SignalDatabase.mms.getMessageRecord(it.messageId)
|
SignalDatabase.mms.getMessageRecord(it.messageId)
|
||||||
}
|
}
|
||||||
|
|
||||||
createStoriesLandingItemData(recipient, messages)
|
var sendingCount: Long = 0
|
||||||
|
var failureCount: Long = 0
|
||||||
|
|
||||||
|
if (recipient.isMyStory) {
|
||||||
|
SignalDatabase.mms.getMessages(results.map { it.messageId }).use { reader ->
|
||||||
|
var messageRecord: MessageRecord? = reader.getNext()
|
||||||
|
while (messageRecord != null) {
|
||||||
|
if (messageRecord.isOutgoing && (messageRecord.isPending || messageRecord.isMediaPending)) {
|
||||||
|
sendingCount++
|
||||||
|
} else if (messageRecord.isFailed) {
|
||||||
|
failureCount++
|
||||||
|
}
|
||||||
|
|
||||||
|
messageRecord = reader.getNext()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
createStoriesLandingItemData(recipient, messages, sendingCount, failureCount)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (observables.isEmpty()) {
|
if (observables.isEmpty()) {
|
||||||
|
@ -80,7 +99,7 @@ class StoriesLandingRepository(context: Context) {
|
||||||
}.subscribeOn(Schedulers.io())
|
}.subscribeOn(Schedulers.io())
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createStoriesLandingItemData(sender: Recipient, messageRecords: List<MessageRecord>): Observable<StoriesLandingItemData> {
|
private fun createStoriesLandingItemData(sender: Recipient, messageRecords: List<MessageRecord>, sendingCount: Long, failureCount: Long): Observable<StoriesLandingItemData> {
|
||||||
val itemDataObservable = Observable.create<StoriesLandingItemData> { emitter ->
|
val itemDataObservable = Observable.create<StoriesLandingItemData> { emitter ->
|
||||||
fun refresh(sender: Recipient) {
|
fun refresh(sender: Recipient) {
|
||||||
val primaryIndex = messageRecords.indexOfFirst { !it.isOutgoing && it.viewedReceiptCount == 0 }.takeIf { it > -1 } ?: 0
|
val primaryIndex = messageRecords.indexOfFirst { !it.isOutgoing && it.viewedReceiptCount == 0 }.takeIf { it > -1 } ?: 0
|
||||||
|
@ -93,7 +112,9 @@ class StoriesLandingRepository(context: Context) {
|
||||||
primaryStory = ConversationMessage.ConversationMessageFactory.createWithUnresolvedData(context, messageRecords[primaryIndex]),
|
primaryStory = ConversationMessage.ConversationMessageFactory.createWithUnresolvedData(context, messageRecords[primaryIndex]),
|
||||||
secondaryStory = if (sender.isMyStory) messageRecords.drop(1).firstOrNull()?.let {
|
secondaryStory = if (sender.isMyStory) messageRecords.drop(1).firstOrNull()?.let {
|
||||||
ConversationMessage.ConversationMessageFactory.createWithUnresolvedData(context, it)
|
ConversationMessage.ConversationMessageFactory.createWithUnresolvedData(context, it)
|
||||||
} else null
|
} else null,
|
||||||
|
sendingCount = sendingCount,
|
||||||
|
failureCount = failureCount
|
||||||
)
|
)
|
||||||
|
|
||||||
emitter.onNext(itemData)
|
emitter.onNext(itemData)
|
||||||
|
|
|
@ -21,6 +21,7 @@ import org.thoughtcrime.securesms.database.model.MmsMessageRecord
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
import org.thoughtcrime.securesms.stories.StoryTextPostModel
|
import org.thoughtcrime.securesms.stories.StoryTextPostModel
|
||||||
import org.thoughtcrime.securesms.stories.dialogs.StoryContextMenu
|
import org.thoughtcrime.securesms.stories.dialogs.StoryContextMenu
|
||||||
|
import org.thoughtcrime.securesms.stories.dialogs.StoryDialogs
|
||||||
import org.thoughtcrime.securesms.stories.viewer.StoryViewerActivity
|
import org.thoughtcrime.securesms.stories.viewer.StoryViewerActivity
|
||||||
import org.thoughtcrime.securesms.util.LifecycleDisposable
|
import org.thoughtcrime.securesms.util.LifecycleDisposable
|
||||||
import org.thoughtcrime.securesms.util.Util
|
import org.thoughtcrime.securesms.util.Util
|
||||||
|
@ -80,8 +81,9 @@ class MyStoriesFragment : DSLSettingsFragment(
|
||||||
if (it.distributionStory.messageRecord.isIdentityMismatchFailure) {
|
if (it.distributionStory.messageRecord.isIdentityMismatchFailure) {
|
||||||
SafetyNumberChangeDialog.show(requireContext(), childFragmentManager, it.distributionStory.messageRecord)
|
SafetyNumberChangeDialog.show(requireContext(), childFragmentManager, it.distributionStory.messageRecord)
|
||||||
} else {
|
} else {
|
||||||
lifecycleDisposable += viewModel.resend(it.distributionStory.messageRecord).subscribe()
|
StoryDialogs.resendStory(requireContext()) {
|
||||||
Toast.makeText(requireContext(), R.string.message_recipients_list_item__resend, Toast.LENGTH_SHORT).show()
|
lifecycleDisposable += viewModel.resend(it.distributionStory.messageRecord).subscribe()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
val recipient = if (it.distributionStory.messageRecord.recipient.isGroup) {
|
val recipient = if (it.distributionStory.messageRecord.recipient.isGroup) {
|
||||||
|
|
|
@ -3,7 +3,6 @@ package org.thoughtcrime.securesms.stories.my
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import androidx.core.content.ContextCompat
|
|
||||||
import org.signal.core.util.DimensionUnit
|
import org.signal.core.util.DimensionUnit
|
||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
import org.thoughtcrime.securesms.components.ThumbnailView
|
import org.thoughtcrime.securesms.components.ThumbnailView
|
||||||
|
@ -16,7 +15,6 @@ import org.thoughtcrime.securesms.mms.GlideApp
|
||||||
import org.thoughtcrime.securesms.mms.Slide
|
import org.thoughtcrime.securesms.mms.Slide
|
||||||
import org.thoughtcrime.securesms.stories.StoryTextPostModel
|
import org.thoughtcrime.securesms.stories.StoryTextPostModel
|
||||||
import org.thoughtcrime.securesms.util.DateUtils
|
import org.thoughtcrime.securesms.util.DateUtils
|
||||||
import org.thoughtcrime.securesms.util.SpanUtil
|
|
||||||
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
|
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
|
||||||
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
|
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
|
||||||
import org.thoughtcrime.securesms.util.adapter.mapping.MappingViewHolder
|
import org.thoughtcrime.securesms.util.adapter.mapping.MappingViewHolder
|
||||||
|
@ -90,11 +88,13 @@ object MyStoriesItem {
|
||||||
moreTarget.setOnClickListener { showContextMenu(model) }
|
moreTarget.setOnClickListener { showContextMenu(model) }
|
||||||
presentDateOrStatus(model)
|
presentDateOrStatus(model)
|
||||||
|
|
||||||
viewCount.text = context.resources.getQuantityString(
|
if (model.distributionStory.messageRecord.isSent) {
|
||||||
R.plurals.MyStories__d_views,
|
viewCount.text = context.resources.getQuantityString(
|
||||||
model.distributionStory.messageRecord.viewedReceiptCount,
|
R.plurals.MyStories__d_views,
|
||||||
model.distributionStory.messageRecord.viewedReceiptCount
|
model.distributionStory.messageRecord.viewedReceiptCount,
|
||||||
)
|
model.distributionStory.messageRecord.viewedReceiptCount
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
if (STATUS_CHANGE in payload) {
|
if (STATUS_CHANGE in payload) {
|
||||||
return
|
return
|
||||||
|
@ -116,12 +116,16 @@ object MyStoriesItem {
|
||||||
private fun presentDateOrStatus(model: Model) {
|
private fun presentDateOrStatus(model: Model) {
|
||||||
if (model.distributionStory.messageRecord.isPending || model.distributionStory.messageRecord.isMediaPending) {
|
if (model.distributionStory.messageRecord.isPending || model.distributionStory.messageRecord.isMediaPending) {
|
||||||
errorIndicator.visible = false
|
errorIndicator.visible = false
|
||||||
date.setText(R.string.StoriesLandingItem__sending)
|
date.visible = false
|
||||||
|
viewCount.setText(R.string.StoriesLandingItem__sending)
|
||||||
} else if (model.distributionStory.messageRecord.isFailed) {
|
} else if (model.distributionStory.messageRecord.isFailed) {
|
||||||
errorIndicator.visible = true
|
errorIndicator.visible = true
|
||||||
date.text = SpanUtil.color(ContextCompat.getColor(context, R.color.signal_alert_primary), context.getString(R.string.StoriesLandingItem__couldnt_send))
|
date.visible = true
|
||||||
|
viewCount.setText(R.string.StoriesLandingItem__send_failed)
|
||||||
|
date.setText(R.string.StoriesLandingItem__tap_to_retry)
|
||||||
} else {
|
} else {
|
||||||
errorIndicator.visible = false
|
errorIndicator.visible = false
|
||||||
|
date.visible = true
|
||||||
date.text = DateUtils.getBriefRelativeTimeSpanString(context, Locale.getDefault(), model.distributionStory.messageRecord.dateSent)
|
date.text = DateUtils.getBriefRelativeTimeSpanString(context, Locale.getDefault(), model.distributionStory.messageRecord.dateSent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,6 +103,10 @@ class StoryGroupReplyFragment :
|
||||||
private lateinit var composer: StoryReplyComposer
|
private lateinit var composer: StoryReplyComposer
|
||||||
private var currentChild: StoryViewsAndRepliesPagerParent.Child? = null
|
private var currentChild: StoryViewsAndRepliesPagerParent.Child? = null
|
||||||
|
|
||||||
|
private var resendBody: CharSequence? = null
|
||||||
|
private var resendMentions: List<Mention> = emptyList()
|
||||||
|
private var resendReaction: String? = null
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
SignalExecutors.BOUNDED.execute {
|
SignalExecutors.BOUNDED.execute {
|
||||||
RetrieveProfileJob.enqueue(groupRecipientId)
|
RetrieveProfileJob.enqueue(groupRecipientId)
|
||||||
|
@ -226,9 +230,6 @@ class StoryGroupReplyFragment :
|
||||||
recyclerView.isNestedScrollingEnabled = currentChild == StoryViewsAndRepliesPagerParent.Child.REPLIES && !(mentionsViewModel.isShowing.value ?: false)
|
recyclerView.isNestedScrollingEnabled = currentChild == StoryViewsAndRepliesPagerParent.Child.REPLIES && !(mentionsViewModel.isShowing.value ?: false)
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
||||||
performSend(body, mentions)
|
performSend(body, mentions)
|
||||||
|
@ -262,7 +263,26 @@ class StoryGroupReplyFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sendReaction(emoji: String) {
|
private fun sendReaction(emoji: String) {
|
||||||
lifecycleDisposable += StoryGroupReplySender.sendReaction(requireContext(), storyId, emoji).subscribe()
|
lifecycleDisposable += StoryGroupReplySender.sendReaction(requireContext(), storyId, emoji)
|
||||||
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
|
.subscribeBy(
|
||||||
|
onError = { error ->
|
||||||
|
if (error is UntrustedRecords.UntrustedRecordsException) {
|
||||||
|
resendReaction = emoji
|
||||||
|
|
||||||
|
SafetyNumberChangeDialog.show(childFragmentManager, error.untrustedRecords)
|
||||||
|
} else {
|
||||||
|
Log.w(TAG, "Failed to send reply", error)
|
||||||
|
val context = context
|
||||||
|
if (context != null) {
|
||||||
|
Toast.makeText(context, R.string.message_details_recipient__failed_to_send, Toast.LENGTH_SHORT).show()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onComplete = {
|
||||||
|
snapToTopDataObserver.requestScrollPosition(0)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onKeyEvent(keyEvent: KeyEvent?) = Unit
|
override fun onKeyEvent(keyEvent: KeyEvent?) = Unit
|
||||||
|
@ -385,8 +405,11 @@ class StoryGroupReplyFragment :
|
||||||
|
|
||||||
override fun onSendAnywayAfterSafetyNumberChange(changedRecipients: MutableList<RecipientId>) {
|
override fun onSendAnywayAfterSafetyNumberChange(changedRecipients: MutableList<RecipientId>) {
|
||||||
val resendBody = resendBody
|
val resendBody = resendBody
|
||||||
|
val resendReaction = resendReaction
|
||||||
if (resendBody != null) {
|
if (resendBody != null) {
|
||||||
performSend(resendBody, resendMentions)
|
performSend(resendBody, resendMentions)
|
||||||
|
} else if (resendReaction != null) {
|
||||||
|
sendReaction(resendReaction)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -397,6 +420,7 @@ class StoryGroupReplyFragment :
|
||||||
override fun onCanceled() {
|
override fun onCanceled() {
|
||||||
resendBody = null
|
resendBody = null
|
||||||
resendMentions = emptyList()
|
resendMentions = emptyList()
|
||||||
|
resendReaction = null
|
||||||
}
|
}
|
||||||
|
|
||||||
interface Callback {
|
interface Callback {
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/safety_number_change_recipient_view"
|
android:id="@+id/safety_number_change_recipient_view"
|
||||||
style="@style/Signal.Widget.Button.Large.Secondary"
|
style="@style/Signal.Widget.Button.Dialog"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:minWidth="0dp"
|
android:minWidth="0dp"
|
||||||
|
|
|
@ -27,13 +27,13 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="16dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:textAppearance="@style/TextAppearance.Signal.Body1.Bold"
|
android:textAppearance="@style/TextAppearance.Signal.Body1.Bold"
|
||||||
app:layout_constraintBottom_toTopOf="@id/date"
|
app:layout_constraintBottom_toTopOf="@id/date"
|
||||||
app:layout_constraintStart_toEndOf="@id/story"
|
app:layout_constraintStart_toEndOf="@+id/error_indicator"
|
||||||
app:layout_constraintTop_toTopOf="parent"
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
app:layout_constraintVertical_chainStyle="packed"
|
app:layout_constraintVertical_chainStyle="packed"
|
||||||
|
app:layout_goneMarginStart="20dp"
|
||||||
tools:text="12 views" />
|
tools:text="12 views" />
|
||||||
|
|
||||||
<androidx.appcompat.widget.AppCompatImageView
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
@ -45,7 +45,7 @@
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/date"
|
app:layout_constraintBottom_toBottomOf="@id/date"
|
||||||
app:layout_constraintStart_toEndOf="@id/story"
|
app:layout_constraintStart_toEndOf="@id/story"
|
||||||
app:layout_constraintTop_toTopOf="@id/date"
|
app:layout_constraintTop_toTopOf="@+id/view_count"
|
||||||
app:srcCompat="@drawable/ic_error_outline_24"
|
app:srcCompat="@drawable/ic_error_outline_24"
|
||||||
app:tint="@color/signal_alert_primary"
|
app:tint="@color/signal_alert_primary"
|
||||||
tools:visibility="visible" />
|
tools:visibility="visible" />
|
||||||
|
@ -54,11 +54,10 @@
|
||||||
android:id="@+id/date"
|
android:id="@+id/date"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="7dp"
|
|
||||||
android:layout_marginEnd="16dp"
|
|
||||||
android:textAppearance="@style/TextAppearance.Signal.Body2"
|
android:textAppearance="@style/TextAppearance.Signal.Body2"
|
||||||
android:textColor="@color/signal_text_secondary"
|
android:textColor="@color/signal_text_secondary"
|
||||||
app:layout_constraintStart_toEndOf="@id/error_indicator"
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="@+id/view_count"
|
||||||
app:layout_constraintTop_toBottomOf="@id/view_count"
|
app:layout_constraintTop_toBottomOf="@id/view_count"
|
||||||
app:layout_goneMarginStart="16dp"
|
app:layout_goneMarginStart="16dp"
|
||||||
tools:text="10m" />
|
tools:text="10m" />
|
||||||
|
|
|
@ -4430,8 +4430,12 @@
|
||||||
<string name="StoriesLandingItem__go_to_chat">Go to chat</string>
|
<string name="StoriesLandingItem__go_to_chat">Go to chat</string>
|
||||||
<!-- Label when a story is pending sending -->
|
<!-- Label when a story is pending sending -->
|
||||||
<string name="StoriesLandingItem__sending">Sending…</string>
|
<string name="StoriesLandingItem__sending">Sending…</string>
|
||||||
|
<!-- Label when multiple stories are pending sending -->
|
||||||
|
<string name="StoriesLandingItem__sending_d">Sending %1$d…</string>
|
||||||
<!-- Label when a story fails to send -->
|
<!-- Label when a story fails to send -->
|
||||||
<string name="StoriesLandingItem__couldnt_send">Couldn\'t send</string>
|
<string name="StoriesLandingItem__send_failed">Send failed</string>
|
||||||
|
<!-- Status label when a story fails to send indicating user action to retry -->
|
||||||
|
<string name="StoriesLandingItem__tap_to_retry">Tap to retry</string>
|
||||||
<!-- Title of dialog confirming decision to hide a story -->
|
<!-- Title of dialog confirming decision to hide a story -->
|
||||||
<string name="StoriesLandingFragment__hide_story">Hide story?</string>
|
<string name="StoriesLandingFragment__hide_story">Hide story?</string>
|
||||||
<!-- Message of dialog confirming decision to hide a story -->
|
<!-- Message of dialog confirming decision to hide a story -->
|
||||||
|
@ -4580,6 +4584,10 @@
|
||||||
<string name="StoryDialogs__add_to_story">Add to story</string>
|
<string name="StoryDialogs__add_to_story">Add to story</string>
|
||||||
<!-- First time share to story dialog: Neutral action to edit who can view "My Story" -->
|
<!-- First time share to story dialog: Neutral action to edit who can view "My Story" -->
|
||||||
<string name="StoryDialogs__edit_viewers">Edit viewers</string>
|
<string name="StoryDialogs__edit_viewers">Edit viewers</string>
|
||||||
|
<!-- Error message shown when a failure occurs during story send -->
|
||||||
|
<string name="StoryDialogs__story_could_not_be_sent">Story could not be sent. Check your connection and try again.</string>
|
||||||
|
<!-- Error message dialog button to resend a previously failed story send -->
|
||||||
|
<string name="StoryDialogs__send">Send</string>
|
||||||
<!-- Privacy Settings toggle title for stories -->
|
<!-- Privacy Settings toggle title for stories -->
|
||||||
<string name="PrivacySettingsFragment__share_and_view_stories">Share & View Stories</string>
|
<string name="PrivacySettingsFragment__share_and_view_stories">Share & View Stories</string>
|
||||||
<!-- Privacy Settings toggle summary for stories -->
|
<!-- Privacy Settings toggle summary for stories -->
|
||||||
|
|
Ładowanie…
Reference in New Issue