mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-21 00:59:49 +01:00
Add in-chat payment activation requests.
Co-authored-by: Varsha <varsha@mobilecoin.com>
This commit is contained in:
@@ -39,7 +39,10 @@ import androidx.annotation.Nullable;
|
||||
import androidx.core.content.ContextCompat;
|
||||
import androidx.fragment.app.Fragment;
|
||||
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import org.signal.core.util.ThreadUtil;
|
||||
import org.signal.core.util.concurrent.SimpleTask;
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.attachments.Attachment;
|
||||
@@ -52,27 +55,36 @@ import org.thoughtcrime.securesms.components.location.SignalPlace;
|
||||
import org.thoughtcrime.securesms.conversation.MessageSendType;
|
||||
import org.thoughtcrime.securesms.database.AttachmentDatabase;
|
||||
import org.thoughtcrime.securesms.database.MediaDatabase;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.giph.ui.GiphyActivity;
|
||||
import org.thoughtcrime.securesms.maps.PlacePickerActivity;
|
||||
import org.thoughtcrime.securesms.mediapreview.MediaIntentFactory;
|
||||
import org.thoughtcrime.securesms.mediapreview.MediaPreviewV2Fragment;
|
||||
import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionActivity;
|
||||
import org.thoughtcrime.securesms.payments.CanNotSendPaymentDialog;
|
||||
import org.thoughtcrime.securesms.payments.MobileCoinPublicAddress;
|
||||
import org.thoughtcrime.securesms.payments.PaymentsAddressException;
|
||||
import org.thoughtcrime.securesms.payments.create.CreatePaymentFragmentArgs;
|
||||
import org.thoughtcrime.securesms.payments.preferences.PaymentsActivity;
|
||||
import org.thoughtcrime.securesms.payments.preferences.RecipientHasNotEnabledPaymentsDialog;
|
||||
import org.thoughtcrime.securesms.payments.preferences.model.PayeeParcelable;
|
||||
import org.thoughtcrime.securesms.permissions.Permissions;
|
||||
import org.thoughtcrime.securesms.providers.BlobProvider;
|
||||
import org.thoughtcrime.securesms.providers.DeprecatedPersistentBlobProvider;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
import org.thoughtcrime.securesms.util.BitmapUtil;
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||
import org.thoughtcrime.securesms.util.MediaUtil;
|
||||
import org.thoughtcrime.securesms.util.ProfileUtil;
|
||||
import org.thoughtcrime.securesms.util.ViewUtil;
|
||||
import org.thoughtcrime.securesms.util.concurrent.AssertedSuccessListener;
|
||||
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture;
|
||||
import org.thoughtcrime.securesms.util.concurrent.ListenableFuture.Listener;
|
||||
import org.thoughtcrime.securesms.util.concurrent.SettableFuture;
|
||||
import org.thoughtcrime.securesms.util.views.Stub;
|
||||
import org.whispersystems.signalservice.api.util.ExpiringProfileCredentialUtil;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
@@ -81,6 +93,7 @@ import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
||||
public class AttachmentManager {
|
||||
@@ -419,11 +432,45 @@ public class AttachmentManager {
|
||||
fragment.startActivityForResult(intent, requestCode);
|
||||
}
|
||||
|
||||
public static void selectPayment(@NonNull Fragment fragment, @NonNull RecipientId recipientId) {
|
||||
Intent intent = new Intent(fragment.requireContext(), PaymentsActivity.class);
|
||||
intent.putExtra(PaymentsActivity.EXTRA_PAYMENTS_STARTING_ACTION, R.id.action_directly_to_createPayment);
|
||||
intent.putExtra(PaymentsActivity.EXTRA_STARTING_ARGUMENTS, new CreatePaymentFragmentArgs.Builder(new PayeeParcelable(recipientId)).build().toBundle());
|
||||
fragment.startActivity(intent);
|
||||
public static void selectPayment(@NonNull Fragment fragment, @NonNull Recipient recipient) {
|
||||
if (!ExpiringProfileCredentialUtil.isValid(recipient.getExpiringProfileKeyCredential())) {
|
||||
CanNotSendPaymentDialog.show(fragment.requireContext());
|
||||
return;
|
||||
}
|
||||
|
||||
SimpleTask.run(fragment.getViewLifecycleOwner().getLifecycle(),
|
||||
() -> {
|
||||
try {
|
||||
return ProfileUtil.getAddressForRecipient(recipient);
|
||||
} catch (IOException | PaymentsAddressException e) {
|
||||
Log.w(TAG, "Could not get address for recipient: ", e);
|
||||
return null;
|
||||
}
|
||||
},
|
||||
(address) -> {
|
||||
if (address != null) {
|
||||
Intent intent = new Intent(fragment.requireContext(), PaymentsActivity.class);
|
||||
intent.putExtra(PaymentsActivity.EXTRA_PAYMENTS_STARTING_ACTION, R.id.action_directly_to_createPayment);
|
||||
intent.putExtra(PaymentsActivity.EXTRA_STARTING_ARGUMENTS, new CreatePaymentFragmentArgs.Builder(new PayeeParcelable(recipient.getId())).build().toBundle());
|
||||
fragment.startActivity(intent);
|
||||
} else if (FeatureFlags.paymentsRequestActivateFlow()) {
|
||||
showRequestToActivatePayments(fragment.requireContext(), recipient);
|
||||
} else {
|
||||
RecipientHasNotEnabledPaymentsDialog.show(fragment.requireContext());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static void showRequestToActivatePayments(@NonNull Context context, @NonNull Recipient recipient) {
|
||||
new MaterialAlertDialogBuilder(context)
|
||||
.setTitle(context.getString(R.string.AttachmentManager__not_activated_payments, recipient.getShortDisplayName(context)))
|
||||
.setMessage(context.getString(R.string.AttachmentManager__request_to_activate_payments))
|
||||
.setPositiveButton(context.getString(R.string.AttachmentManager__send_request), (dialog, which) -> {
|
||||
OutgoingRequestToActivatePaymentMessages outgoingMessage = new OutgoingRequestToActivatePaymentMessages(recipient, System.currentTimeMillis(), 0);
|
||||
MessageSender.send(context, outgoingMessage, SignalDatabase.threads().getOrCreateThreadIdFor(recipient), false, null, null);
|
||||
})
|
||||
.setNegativeButton(context.getString(R.string.AttachmentManager__cancel), null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private @Nullable Uri getSlideUri() {
|
||||
|
||||
@@ -38,7 +38,9 @@ class IncomingMediaMessage(
|
||||
sharedContacts: List<Contact> = emptyList(),
|
||||
linkPreviews: List<LinkPreview> = emptyList(),
|
||||
mentions: List<Mention> = emptyList(),
|
||||
val giftBadge: GiftBadge? = null
|
||||
val giftBadge: GiftBadge? = null,
|
||||
val isActivatePaymentsRequest: Boolean = false,
|
||||
val isPaymentsActivated: Boolean = false
|
||||
) {
|
||||
|
||||
val attachments: List<Attachment> = ArrayList(attachments)
|
||||
@@ -61,7 +63,9 @@ class IncomingMediaMessage(
|
||||
expirationUpdate: Boolean,
|
||||
viewOnce: Boolean,
|
||||
unidentified: Boolean,
|
||||
sharedContacts: Optional<List<Contact>>
|
||||
sharedContacts: Optional<List<Contact>>,
|
||||
activatePaymentsRequest: Boolean,
|
||||
paymentsActivated: Boolean
|
||||
) : this(
|
||||
from = from,
|
||||
groupId = groupId.orElse(null),
|
||||
@@ -79,6 +83,8 @@ class IncomingMediaMessage(
|
||||
serverGuid = null,
|
||||
attachments = attachments?.let { ArrayList<Attachment>(it) } ?: emptyList(),
|
||||
sharedContacts = ArrayList<Contact>(sharedContacts.orElse(emptyList())),
|
||||
isActivatePaymentsRequest = activatePaymentsRequest,
|
||||
isPaymentsActivated = paymentsActivated
|
||||
)
|
||||
|
||||
constructor(
|
||||
@@ -103,7 +109,9 @@ class IncomingMediaMessage(
|
||||
mentions: Optional<List<Mention>>,
|
||||
sticker: Optional<Attachment>,
|
||||
serverGuid: String?,
|
||||
giftBadge: GiftBadge?
|
||||
giftBadge: GiftBadge?,
|
||||
activatePaymentsRequest: Boolean,
|
||||
paymentsActivated: Boolean
|
||||
) : this(
|
||||
from = from,
|
||||
groupId = if (group.isPresent) GroupId.v2(group.get().masterKey) else null,
|
||||
@@ -126,6 +134,8 @@ class IncomingMediaMessage(
|
||||
sharedContacts = sharedContacts.orElse(emptyList()),
|
||||
linkPreviews = linkPreviews.orElse(emptyList()),
|
||||
mentions = mentions.orElse(emptyList()),
|
||||
giftBadge = giftBadge
|
||||
giftBadge = giftBadge,
|
||||
isActivatePaymentsRequest = activatePaymentsRequest,
|
||||
isPaymentsActivated = paymentsActivated
|
||||
)
|
||||
}
|
||||
|
||||
@@ -193,6 +193,14 @@ public class OutgoingMediaMessage {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isRequestToActivatePayments() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isPaymentsActivated() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public long getSentTimeMillis() {
|
||||
return sentTimeMillis;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
package org.thoughtcrime.securesms.mms
|
||||
|
||||
import org.thoughtcrime.securesms.database.ThreadDatabase
|
||||
import org.thoughtcrime.securesms.database.model.StoryType
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import java.util.LinkedList
|
||||
|
||||
/**
|
||||
* Specialized message sent to request someone activate payments.
|
||||
*/
|
||||
class OutgoingRequestToActivatePaymentMessages(
|
||||
recipient: Recipient,
|
||||
sentTimeMillis: Long,
|
||||
expiresIn: Long
|
||||
) : OutgoingSecureMediaMessage(
|
||||
recipient,
|
||||
"",
|
||||
LinkedList(),
|
||||
sentTimeMillis,
|
||||
ThreadDatabase.DistributionTypes.CONVERSATION,
|
||||
expiresIn,
|
||||
false,
|
||||
StoryType.NONE,
|
||||
null,
|
||||
false,
|
||||
null, emptyList(), emptyList(), emptyList(),
|
||||
null
|
||||
) {
|
||||
override fun isRequestToActivatePayments(): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Specialized message sent to indicate you activated payments. Intended to only
|
||||
* be sent to those that sent requests prior to activation.
|
||||
*/
|
||||
class OutgoingPaymentsActivatedMessages(
|
||||
recipient: Recipient,
|
||||
sentTimeMillis: Long,
|
||||
expiresIn: Long
|
||||
) : OutgoingSecureMediaMessage(
|
||||
recipient,
|
||||
"",
|
||||
LinkedList(),
|
||||
sentTimeMillis,
|
||||
ThreadDatabase.DistributionTypes.CONVERSATION,
|
||||
expiresIn,
|
||||
false,
|
||||
StoryType.NONE,
|
||||
null,
|
||||
false,
|
||||
null, emptyList(), emptyList(), emptyList(),
|
||||
null
|
||||
) {
|
||||
override fun isPaymentsActivated(): Boolean {
|
||||
return true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user