Add import and tombstones for mobile coin payments.

This commit is contained in:
Clark
2024-05-31 17:03:59 -04:00
committed by Cody Henthorne
parent 1e35403c87
commit d85ab37828
19 changed files with 399 additions and 9 deletions

View File

@@ -110,6 +110,7 @@ import org.thoughtcrime.securesms.database.MediaTable;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.database.model.Quote;
import org.thoughtcrime.securesms.database.model.databaseprotos.MessageExtras;
import org.thoughtcrime.securesms.dependencies.AppDependencies;
import org.thoughtcrime.securesms.events.PartProgressEvent;
import org.thoughtcrime.securesms.giph.mp4.GiphyMp4PlaybackPolicy;
@@ -261,6 +262,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
private final TouchDelegateChangedListener touchDelegateChangedListener = new TouchDelegateChangedListener();
private final DoubleTapEditTouchListener doubleTapEditTouchListener = new DoubleTapEditTouchListener();
private final GiftMessageViewCallback giftMessageViewCallback = new GiftMessageViewCallback();
private final PaymentTombstoneClickListener paymentTombstoneClickListener = new PaymentTombstoneClickListener();
private final Context context;
@@ -1038,7 +1040,7 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
bodyText.setText(italics);
bodyText.setVisibility(View.VISIBLE);
bodyText.setOverflowText(null);
} else if (isCaptionlessMms(messageRecord) || isStoryReaction(messageRecord) || isGiftMessage(messageRecord) || messageRecord.isPaymentNotification()) {
} else if (isCaptionlessMms(messageRecord) || isStoryReaction(messageRecord) || isGiftMessage(messageRecord) || messageRecord.isPaymentNotification() || messageRecord.isPaymentTombstone()) {
bodyText.setText(null);
bodyText.setOverflowText(null);
bodyText.setVisibility(View.GONE);
@@ -1396,8 +1398,29 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
MmsMessageRecord mediaMmsMessageRecord = (MmsMessageRecord) messageRecord;
paymentViewStub.setVisibility(View.VISIBLE);
paymentViewStub.get().setOnTombstoneClickListener(paymentTombstoneClickListener);
paymentViewStub.get().bindPayment(conversationRecipient.get(), Objects.requireNonNull(mediaMmsMessageRecord.getPayment()), colorizer);
footer.setVisibility(VISIBLE);
} else if (messageRecord.isPaymentTombstone()) {
if (mediaThumbnailStub.resolved()) mediaThumbnailStub.require().setVisibility(GONE);
if (audioViewStub.resolved()) audioViewStub.get().setVisibility(GONE);
if (documentViewStub.resolved()) documentViewStub.get().setVisibility(GONE);
if (sharedContactStub.resolved()) sharedContactStub.get().setVisibility(GONE);
if (linkPreviewStub.resolved()) linkPreviewStub.get().setVisibility(GONE);
if (stickerStub.resolved()) stickerStub.get().setVisibility(GONE);
if (revealableStub.resolved()) revealableStub.get().setVisibility(GONE);
if (giftViewStub.resolved()) giftViewStub.get().setVisibility(View.GONE);
if (joinCallLinkStub.resolved()) joinCallLinkStub.get().setVisibility(View.GONE);
MmsMessageRecord mediaMmsMessageRecord = (MmsMessageRecord) messageRecord;
paymentViewStub.setVisibility(View.VISIBLE);
paymentViewStub.get().setOnTombstoneClickListener(paymentTombstoneClickListener);
MessageExtras messageExtras = mediaMmsMessageRecord.getMessageExtras();
paymentViewStub.get().bindPaymentTombstone(mediaMmsMessageRecord.isOutgoing(), conversationRecipient.get(), messageExtras == null ? null : messageExtras.paymentTombstone, colorizer);
footer.setVisibility(VISIBLE);
} else {
if (mediaThumbnailStub.resolved()) mediaThumbnailStub.require().setVisibility(View.GONE);
@@ -2352,6 +2375,16 @@ public final class ConversationItem extends RelativeLayout implements BindableCo
return null;
}
private class PaymentTombstoneClickListener implements View.OnClickListener {
@Override
public void onClick(View v) {
if (eventListener != null) {
eventListener.onPaymentTombstoneClicked();
} else {
passthroughClickListener.onClick(v);
}
}
}
private class SharedContactEventListener implements SharedContactView.EventListener {
@Override
public void onAddToContactsClicked(@NonNull Contact contact) {

View File

@@ -135,7 +135,7 @@ public final class MenuState {
hasGift = true;
}
if (messageRecord.isPaymentNotification()) {
if (messageRecord.isPaymentNotification() || messageRecord.isPaymentTombstone()) {
hasPayment = true;
}
}

View File

@@ -14,11 +14,14 @@ import org.signal.core.util.dp
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.quotes.QuoteViewColorTheme
import org.thoughtcrime.securesms.conversation.colors.Colorizer
import org.thoughtcrime.securesms.database.model.databaseprotos.PaymentTombstone
import org.thoughtcrime.securesms.databinding.PaymentMessageViewBinding
import org.thoughtcrime.securesms.payments.CryptoValueUtil
import org.thoughtcrime.securesms.payments.Direction
import org.thoughtcrime.securesms.payments.Payment
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.visible
import org.whispersystems.signalservice.api.payments.Money
/**
* Showing payment information in conversation.
@@ -30,11 +33,25 @@ class PaymentMessageView @JvmOverloads constructor(
private val binding: PaymentMessageViewBinding
private var onTombstoneClickListener: OnClickListener? = null
init {
binding = PaymentMessageViewBinding.inflate(LayoutInflater.from(context), this, true)
}
fun bindPayment(recipient: Recipient, payment: Payment, colorizer: Colorizer) {
fun bindPayment(recipient: Recipient, payment: Payment?, colorizer: Colorizer) {
if (payment == null) {
binding.paymentTombstone.visible = true
binding.paymentAmount.visible = false
binding.paymentInprogress.visible = false
binding.paymentAmountLayout.setOnClickListener {
onTombstoneClickListener?.onClick(it)
}
return
}
binding.paymentAmountLayout.setOnClickListener(null)
binding.paymentTombstone.visible = false
val outgoing = payment.direction == Direction.SENT
binding.paymentDirection.apply {
@@ -69,6 +86,51 @@ class PaymentMessageView @JvmOverloads constructor(
ViewCompat.setBackgroundTintList(binding.paymentAmountLayout, ColorStateList.valueOf(quoteViewColorTheme.getBackgroundColor(context)))
}
fun bindPaymentTombstone(outgoing: Boolean, recipient: Recipient, paymentTombstone: PaymentTombstone?, colorizer: Colorizer) {
val amount: Money? = if (paymentTombstone?.amount != null) {
CryptoValueUtil.cryptoValueToMoney(paymentTombstone.amount)
} else {
null
}
binding.paymentDirection.apply {
if (outgoing) {
text = context.getString(R.string.PaymentMessageView_you_sent_s, recipient.getShortDisplayName(context))
setTextColor(colorizer.getOutgoingFooterTextColor(context))
} else {
text = context.getString(R.string.PaymentMessageView_s_sent_you, recipient.getShortDisplayName(context))
setTextColor(colorizer.getIncomingFooterTextColor(context, recipient.hasWallpaper))
}
}
if (amount == null) {
binding.paymentTombstone.visible = true
binding.paymentAmount.visible = false
binding.paymentInprogress.visible = false
binding.paymentAmountLayout.setOnClickListener {
onTombstoneClickListener?.onClick(it)
}
return
}
val note = paymentTombstone?.note ?: ""
binding.paymentAmountLayout.setOnClickListener(null)
binding.paymentTombstone.visible = false
binding.paymentNote.apply {
text = note
visible = note.isNotEmpty()
setTextColor(if (outgoing) colorizer.getOutgoingBodyTextColor(context) else colorizer.getIncomingBodyTextColor(context, recipient.hasWallpaper))
}
val quoteViewColorTheme = QuoteViewColorTheme.resolveTheme(outgoing, false, recipient.hasWallpaper)
binding.paymentAmount.visible = true
binding.paymentInprogress.visible = false
binding.paymentAmount.setTextColor(quoteViewColorTheme.getForegroundColor(context))
binding.paymentAmount.setMoney(amount, 0L, currencyTypefaceSpan)
ViewCompat.setBackgroundTintList(binding.paymentAmountLayout, ColorStateList.valueOf(quoteViewColorTheme.getBackgroundColor(context)))
}
private fun getInProgressDrawable(@ColorInt color: Int): IndeterminateDrawable<CircularProgressIndicatorSpec> {
val spec = CircularProgressIndicatorSpec(context, null).apply {
indicatorInset = 0
@@ -82,6 +144,10 @@ class PaymentMessageView @JvmOverloads constructor(
return drawable
}
fun setOnTombstoneClickListener(listener: OnClickListener?) {
this.onTombstoneClickListener = listener
}
companion object {
private val currencyTypefaceSpan = TypefaceSpan("sans-serif-light")
}

View File

@@ -2367,12 +2367,26 @@ class ConversationFragment :
private fun handleViewPaymentDetails(conversationMessage: ConversationMessage) {
val record: MmsMessageRecord = conversationMessage.messageRecord as? MmsMessageRecord ?: return
val payment = record.payment ?: return
val payment = record.payment
if (payment == null || record.isPaymentTombstone) {
showPaymentTombstoneLearnMoreDialog()
return
}
if (record.isPaymentNotification) {
startActivity(PaymentsActivity.navigateToPaymentDetails(requireContext(), payment.uuid))
}
}
private fun showPaymentTombstoneLearnMoreDialog() {
val dialogBuilder = MaterialAlertDialogBuilder(requireContext())
dialogBuilder
.setTitle(R.string.PaymentTombstoneLearnMoreDialog_title)
.setMessage(R.string.PaymentTombstoneLearnMoreDialog_message)
.setPositiveButton(android.R.string.ok, null)
dialogBuilder.show()
}
private fun handleDisplayDetails(conversationMessage: ConversationMessage) {
val recipientSnapshot = viewModel.recipientSnapshot ?: return
MessageDetailsFragment.create(conversationMessage.messageRecord, recipientSnapshot.id).show(childFragmentManager, null)
@@ -2801,6 +2815,10 @@ class ConversationFragment :
DoubleTapEditEducationSheet(conversationMessage).show(childFragmentManager, DoubleTapEditEducationSheet.KEY)
}
override fun onPaymentTombstoneClicked() {
this@ConversationFragment.showPaymentTombstoneLearnMoreDialog()
}
override fun onMessageWithErrorClicked(messageRecord: MessageRecord) {
val recipientId = viewModel.recipientSnapshot?.id ?: return
if (messageRecord.isIdentityMismatchFailure) {