mirror of
https://github.com/signalapp/Signal-Android.git
synced 2025-12-22 20:18:36 +00:00
Fix in-chat payment view not updating properly.
This commit is contained in:
@@ -6,7 +6,11 @@ import android.text.style.TypefaceSpan
|
|||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.widget.FrameLayout
|
import android.widget.FrameLayout
|
||||||
|
import androidx.annotation.ColorInt
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
|
import com.google.android.material.progressindicator.CircularProgressIndicatorSpec
|
||||||
|
import com.google.android.material.progressindicator.IndeterminateDrawable
|
||||||
|
import org.signal.core.util.dp
|
||||||
import org.thoughtcrime.securesms.R
|
import org.thoughtcrime.securesms.R
|
||||||
import org.thoughtcrime.securesms.components.quotes.QuoteViewColorTheme
|
import org.thoughtcrime.securesms.components.quotes.QuoteViewColorTheme
|
||||||
import org.thoughtcrime.securesms.conversation.colors.Colorizer
|
import org.thoughtcrime.securesms.conversation.colors.Colorizer
|
||||||
@@ -51,12 +55,33 @@ class PaymentMessageView @JvmOverloads constructor(
|
|||||||
|
|
||||||
val quoteViewColorTheme = QuoteViewColorTheme.resolveTheme(outgoing, false, recipient.hasWallpaper())
|
val quoteViewColorTheme = QuoteViewColorTheme.resolveTheme(outgoing, false, recipient.hasWallpaper())
|
||||||
|
|
||||||
binding.paymentAmount.setTextColor(quoteViewColorTheme.getForegroundColor(context))
|
if (payment.state.isInProgress) {
|
||||||
binding.paymentAmount.setMoney(payment.amount, 0L, currencyTypefaceSpan)
|
binding.paymentAmount.visible = false
|
||||||
|
binding.paymentInprogress.visible = true
|
||||||
|
binding.paymentInprogress.setImageDrawable(getInProgressDrawable(quoteViewColorTheme.getForegroundColor(context)))
|
||||||
|
} else {
|
||||||
|
binding.paymentAmount.visible = true
|
||||||
|
binding.paymentInprogress.visible = false
|
||||||
|
binding.paymentAmount.setTextColor(quoteViewColorTheme.getForegroundColor(context))
|
||||||
|
binding.paymentAmount.setMoney(payment.amount, 0L, currencyTypefaceSpan)
|
||||||
|
}
|
||||||
|
|
||||||
ViewCompat.setBackgroundTintList(binding.paymentAmountLayout, ColorStateList.valueOf(quoteViewColorTheme.getBackgroundColor(context)))
|
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
|
||||||
|
indicatorColors = intArrayOf(color)
|
||||||
|
indicatorSize = 20.dp
|
||||||
|
trackThickness = 2.dp
|
||||||
|
}
|
||||||
|
|
||||||
|
val drawable = IndeterminateDrawable.createCircularDrawable(context, spec)
|
||||||
|
drawable.setBounds(0, 0, spec.indicatorSize, spec.indicatorSize)
|
||||||
|
return drawable
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val currencyTypefaceSpan = TypefaceSpan("sans-serif-light")
|
private val currencyTypefaceSpan = TypefaceSpan("sans-serif-light")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -542,6 +542,20 @@ public abstract class MessageTable extends DatabaseTable implements MmsSmsColumn
|
|||||||
return CursorExtensionsKt.readToList(cursor, c -> CursorUtil.requireLong(c, THREAD_ID));
|
return CursorExtensionsKt.readToList(cursor, c -> CursorUtil.requireLong(c, THREAD_ID));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public @Nullable MessageId getPaymentMessage(@NonNull UUID paymentUuid) {
|
||||||
|
Cursor cursor = SQLiteDatabaseExtensionsKt.select(getReadableDatabase(), ID)
|
||||||
|
.from(getTableName())
|
||||||
|
.where(getTypeField() + " & ? != 0 AND body = ?", Types.SPECIAL_TYPE_PAYMENTS_NOTIFICATION, paymentUuid)
|
||||||
|
.run();
|
||||||
|
|
||||||
|
long id = CursorExtensionsKt.readToSingleLong(cursor, -1);
|
||||||
|
if (id != -1) {
|
||||||
|
return new MessageId(id, getTableName().equals(MmsTable.TABLE_NAME));
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void remapRecipient(@NonNull RecipientId fromId, @NonNull RecipientId toId) {
|
public void remapRecipient(@NonNull RecipientId fromId, @NonNull RecipientId toId) {
|
||||||
ContentValues values = new ContentValues();
|
ContentValues values = new ContentValues();
|
||||||
|
|||||||
@@ -212,7 +212,8 @@ public class MmsTable extends MessageTable {
|
|||||||
"CREATE INDEX IF NOT EXISTS mms_parent_story_id_index ON " + TABLE_NAME + " (" + PARENT_STORY_ID + ");",
|
"CREATE INDEX IF NOT EXISTS mms_parent_story_id_index ON " + TABLE_NAME + " (" + PARENT_STORY_ID + ");",
|
||||||
"CREATE INDEX IF NOT EXISTS mms_thread_story_parent_story_index ON " + TABLE_NAME + " (" + THREAD_ID + ", " + DATE_RECEIVED + "," + STORY_TYPE + "," + PARENT_STORY_ID + ");",
|
"CREATE INDEX IF NOT EXISTS mms_thread_story_parent_story_index ON " + TABLE_NAME + " (" + THREAD_ID + ", " + DATE_RECEIVED + "," + STORY_TYPE + "," + PARENT_STORY_ID + ");",
|
||||||
"CREATE INDEX IF NOT EXISTS mms_quote_id_quote_author_index ON " + TABLE_NAME + "(" + QUOTE_ID + ", " + QUOTE_AUTHOR + ");",
|
"CREATE INDEX IF NOT EXISTS mms_quote_id_quote_author_index ON " + TABLE_NAME + "(" + QUOTE_ID + ", " + QUOTE_AUTHOR + ");",
|
||||||
"CREATE INDEX IF NOT EXISTS mms_exported_index ON " + TABLE_NAME + " (" + EXPORTED + ");"
|
"CREATE INDEX IF NOT EXISTS mms_exported_index ON " + TABLE_NAME + " (" + EXPORTED + ");",
|
||||||
|
"CREATE INDEX IF NOT EXISTS mms_id_msg_box_payment_transactions_index ON " + TABLE_NAME + " (" + ID + "," + MESSAGE_BOX + ") WHERE " + MESSAGE_BOX + " & " + Types.SPECIAL_TYPE_PAYMENTS_NOTIFICATION + " != 0;"
|
||||||
};
|
};
|
||||||
|
|
||||||
private static final String[] MMS_PROJECTION = new String[] {
|
private static final String[] MMS_PROJECTION = new String[] {
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import org.signal.core.util.CursorExtensionsKt;
|
|||||||
import org.signal.core.util.SQLiteDatabaseExtensionsKt;
|
import org.signal.core.util.SQLiteDatabaseExtensionsKt;
|
||||||
import org.signal.core.util.logging.Log;
|
import org.signal.core.util.logging.Log;
|
||||||
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
|
||||||
|
import org.thoughtcrime.securesms.database.model.MessageId;
|
||||||
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
import org.thoughtcrime.securesms.database.model.MessageRecord;
|
||||||
import org.thoughtcrime.securesms.database.model.databaseprotos.CryptoValue;
|
import org.thoughtcrime.securesms.database.model.databaseprotos.CryptoValue;
|
||||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||||
@@ -33,6 +34,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId;
|
|||||||
import org.thoughtcrime.securesms.util.Base64;
|
import org.thoughtcrime.securesms.util.Base64;
|
||||||
import org.signal.core.util.CursorUtil;
|
import org.signal.core.util.CursorUtil;
|
||||||
import org.signal.core.util.SqlUtil;
|
import org.signal.core.util.SqlUtil;
|
||||||
|
import org.thoughtcrime.securesms.util.FeatureFlags;
|
||||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
|
||||||
import org.whispersystems.signalservice.api.payments.Money;
|
import org.whispersystems.signalservice.api.payments.Money;
|
||||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||||
@@ -647,6 +649,10 @@ public final class PaymentTable extends DatabaseTable implements RecipientIdData
|
|||||||
private void notifyUuidChanged(@Nullable UUID uuid) {
|
private void notifyUuidChanged(@Nullable UUID uuid) {
|
||||||
if (uuid != null) {
|
if (uuid != null) {
|
||||||
ApplicationDependencies.getDatabaseObserver().notifyPaymentListeners(uuid);
|
ApplicationDependencies.getDatabaseObserver().notifyPaymentListeners(uuid);
|
||||||
|
MessageId messageId = SignalDatabase.mms().getPaymentMessage(uuid);
|
||||||
|
if (messageId != null) {
|
||||||
|
ApplicationDependencies.getDatabaseObserver().notifyMessageUpdateObservers(messageId);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import org.thoughtcrime.securesms.database.helpers.migration.V161_StorySendMessa
|
|||||||
import org.thoughtcrime.securesms.database.helpers.migration.V162_ThreadUnreadSelfMentionCountFixup
|
import org.thoughtcrime.securesms.database.helpers.migration.V162_ThreadUnreadSelfMentionCountFixup
|
||||||
import org.thoughtcrime.securesms.database.helpers.migration.V163_RemoteMegaphoneSnoozeSupportMigration
|
import org.thoughtcrime.securesms.database.helpers.migration.V163_RemoteMegaphoneSnoozeSupportMigration
|
||||||
import org.thoughtcrime.securesms.database.helpers.migration.V164_ThreadDatabaseReadIndexMigration
|
import org.thoughtcrime.securesms.database.helpers.migration.V164_ThreadDatabaseReadIndexMigration
|
||||||
|
import org.thoughtcrime.securesms.database.helpers.migration.V165_MmsMessageBoxPaymentTransactionIndexMigration
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness.
|
* Contains all of the database migrations for [SignalDatabase]. Broken into a separate file for cleanliness.
|
||||||
@@ -28,7 +29,7 @@ object SignalDatabaseMigrations {
|
|||||||
|
|
||||||
val TAG: String = Log.tag(SignalDatabaseMigrations.javaClass)
|
val TAG: String = Log.tag(SignalDatabaseMigrations.javaClass)
|
||||||
|
|
||||||
const val DATABASE_VERSION = 164
|
const val DATABASE_VERSION = 165
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||||
@@ -95,6 +96,10 @@ object SignalDatabaseMigrations {
|
|||||||
if (oldVersion < 164) {
|
if (oldVersion < 164) {
|
||||||
V164_ThreadDatabaseReadIndexMigration.migrate(context, db, oldVersion, newVersion)
|
V164_ThreadDatabaseReadIndexMigration.migrate(context, db, oldVersion, newVersion)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldVersion < 165) {
|
||||||
|
V165_MmsMessageBoxPaymentTransactionIndexMigration.migrate(context, db, oldVersion, newVersion)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
package org.thoughtcrime.securesms.database.helpers.migration
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import net.zetetic.database.sqlcipher.SQLiteDatabase
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds an index to MMS table that only covers id and messages with the type of payment notification to
|
||||||
|
* speed up look ups for payment messages.
|
||||||
|
*/
|
||||||
|
@Suppress("ClassName")
|
||||||
|
object V165_MmsMessageBoxPaymentTransactionIndexMigration : SignalDatabaseMigration {
|
||||||
|
override fun migrate(context: Application, db: SQLiteDatabase, oldVersion: Int, newVersion: Int) {
|
||||||
|
db.execSQL("CREATE INDEX IF NOT EXISTS mms_id_msg_box_payment_transactions_index ON mms (_id, msg_box) WHERE msg_box & 0x300000000 != 0")
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -42,24 +42,7 @@ public final class PaymentNotificationSendJob extends BaseJob {
|
|||||||
private final UUID uuid;
|
private final UUID uuid;
|
||||||
|
|
||||||
public static Job create(@NonNull RecipientId recipientId, @NonNull UUID uuid, @NonNull String queue) {
|
public static Job create(@NonNull RecipientId recipientId, @NonNull UUID uuid, @NonNull String queue) {
|
||||||
if (FeatureFlags.paymentsInChatMessages()) {
|
return new PaymentNotificationSendJobV2(recipientId, uuid);
|
||||||
return new PaymentNotificationSendJobV2(recipientId, uuid);
|
|
||||||
} else {
|
|
||||||
return new PaymentNotificationSendJob(recipientId, uuid, queue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private PaymentNotificationSendJob(@NonNull RecipientId recipientId,
|
|
||||||
@NonNull UUID uuid,
|
|
||||||
@NonNull String queue)
|
|
||||||
{
|
|
||||||
this(new Parameters.Builder()
|
|
||||||
.setQueue(queue)
|
|
||||||
.setLifespan(TimeUnit.DAYS.toMillis(1))
|
|
||||||
.setMaxAttempts(Parameters.UNLIMITED)
|
|
||||||
.build(),
|
|
||||||
recipientId,
|
|
||||||
uuid);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private PaymentNotificationSendJob(@NonNull Parameters parameters,
|
private PaymentNotificationSendJob(@NonNull Parameters parameters,
|
||||||
|
|||||||
@@ -465,21 +465,19 @@ public final class MessageContentProcessor {
|
|||||||
Money.MobileCoin.ZERO,
|
Money.MobileCoin.ZERO,
|
||||||
Money.MobileCoin.ZERO,
|
Money.MobileCoin.ZERO,
|
||||||
paymentNotification.getReceipt(),
|
paymentNotification.getReceipt(),
|
||||||
FeatureFlags.paymentsInChatMessages());
|
true);
|
||||||
|
|
||||||
if (FeatureFlags.paymentsInChatMessages()) {
|
IncomingMediaMessage mediaMessage = IncomingMediaMessage.createIncomingPaymentNotification(senderRecipient.getId(),
|
||||||
IncomingMediaMessage mediaMessage = IncomingMediaMessage.createIncomingPaymentNotification(senderRecipient.getId(),
|
content,
|
||||||
content,
|
receivedTime,
|
||||||
receivedTime,
|
TimeUnit.SECONDS.toMillis(message.getExpiresInSeconds()),
|
||||||
TimeUnit.SECONDS.toMillis(message.getExpiresInSeconds()),
|
uuid);
|
||||||
uuid);
|
|
||||||
|
|
||||||
Optional<InsertResult> insertResult = SignalDatabase.mms().insertSecureDecryptedMessageInbox(mediaMessage, -1);
|
Optional<InsertResult> insertResult = SignalDatabase.mms().insertSecureDecryptedMessageInbox(mediaMessage, -1);
|
||||||
smsMessageId.ifPresent(smsId -> SignalDatabase.sms().deleteMessage(smsId));
|
smsMessageId.ifPresent(smsId -> SignalDatabase.sms().deleteMessage(smsId));
|
||||||
if (insertResult.isPresent()) {
|
if (insertResult.isPresent()) {
|
||||||
messageId = new MessageId(insertResult.get().getMessageId(), true);
|
messageId = new MessageId(insertResult.get().getMessageId(), true);
|
||||||
ApplicationDependencies.getMessageNotifier().updateNotification(context, ConversationId.forConversation(insertResult.get().getThreadId()));
|
ApplicationDependencies.getMessageNotifier().updateNotification(context, ConversationId.forConversation(insertResult.get().getThreadId()));
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (PaymentTable.PublicKeyConflictException e) {
|
} catch (PaymentTable.PublicKeyConflictException e) {
|
||||||
warn(content.getTimestamp(), "Ignoring payment with public key already in database");
|
warn(content.getTimestamp(), "Ignoring payment with public key already in database");
|
||||||
|
|||||||
@@ -105,7 +105,6 @@ public final class FeatureFlags {
|
|||||||
public static final String CREDIT_CARD_DISABLED_REGIONS = "global.donations.ccDisabledRegions";
|
public static final String CREDIT_CARD_DISABLED_REGIONS = "global.donations.ccDisabledRegions";
|
||||||
public static final String PAYPAL_DISABLED_REGIONS = "global.donations.paypalDisabledRegions";
|
public static final String PAYPAL_DISABLED_REGIONS = "global.donations.paypalDisabledRegions";
|
||||||
private static final String CDS_HARD_LIMIT = "android.cds.hardLimit";
|
private static final String CDS_HARD_LIMIT = "android.cds.hardLimit";
|
||||||
private static final String PAYMENTS_IN_CHAT_MESSAGES = "android.payments.inChatMessages";
|
|
||||||
private static final String CHAT_FILTERS = "android.chat.filters";
|
private static final String CHAT_FILTERS = "android.chat.filters";
|
||||||
private static final String PAYPAL_DONATIONS = "android.donations.paypal";
|
private static final String PAYPAL_DONATIONS = "android.donations.paypal";
|
||||||
|
|
||||||
@@ -166,7 +165,6 @@ public final class FeatureFlags {
|
|||||||
PAYPAL_DISABLED_REGIONS,
|
PAYPAL_DISABLED_REGIONS,
|
||||||
KEEP_MUTED_CHATS_ARCHIVED,
|
KEEP_MUTED_CHATS_ARCHIVED,
|
||||||
CDS_HARD_LIMIT,
|
CDS_HARD_LIMIT,
|
||||||
PAYMENTS_IN_CHAT_MESSAGES,
|
|
||||||
CHAT_FILTERS,
|
CHAT_FILTERS,
|
||||||
PAYPAL_DONATIONS
|
PAYPAL_DONATIONS
|
||||||
);
|
);
|
||||||
@@ -232,8 +230,7 @@ public final class FeatureFlags {
|
|||||||
CREDIT_CARD_PAYMENTS,
|
CREDIT_CARD_PAYMENTS,
|
||||||
PAYMENTS_REQUEST_ACTIVATE_FLOW,
|
PAYMENTS_REQUEST_ACTIVATE_FLOW,
|
||||||
KEEP_MUTED_CHATS_ARCHIVED,
|
KEEP_MUTED_CHATS_ARCHIVED,
|
||||||
CDS_HARD_LIMIT,
|
CDS_HARD_LIMIT
|
||||||
PAYMENTS_IN_CHAT_MESSAGES
|
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -550,11 +547,6 @@ public final class FeatureFlags {
|
|||||||
return getBoolean(PAYMENTS_REQUEST_ACTIVATE_FLOW, false);
|
return getBoolean(PAYMENTS_REQUEST_ACTIVATE_FLOW, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Whether client supports processing a payment notification as a in-chat message */
|
|
||||||
public static boolean paymentsInChatMessages() {
|
|
||||||
return getBoolean(PAYMENTS_IN_CHAT_MESSAGES, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether users can enable keeping conversations with incoming messages archived if the conversation is muted.
|
* Whether users can enable keeping conversations with incoming messages archived if the conversation is muted.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -36,6 +36,12 @@
|
|||||||
app:autoSizeTextType="uniform"
|
app:autoSizeTextType="uniform"
|
||||||
app:money="MOB:275000000000000" />
|
app:money="MOB:275000000000000" />
|
||||||
|
|
||||||
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
|
android:id="@+id/payment_inprogress"
|
||||||
|
android:layout_width="20dp"
|
||||||
|
android:layout_height="20dp"
|
||||||
|
android:layout_gravity="center" />
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|
||||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||||
|
|||||||
Reference in New Issue
Block a user