Insert temporary warning update message during message request state.

fork-5.53.8
Cody Henthorne 2021-04-23 15:29:59 -04:00 zatwierdzone przez GitHub
rodzic ad81b310e3
commit 59c49254e7
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: 4AEE18F83AFDEB23
11 zmienionych plików z 263 dodań i 48 usunięć

Wyświetl plik

@ -13,6 +13,7 @@ import org.thoughtcrime.securesms.components.voice.VoiceNotePlaybackState;
import org.thoughtcrime.securesms.contactshare.Contact;
import org.thoughtcrime.securesms.conversation.ConversationItem;
import org.thoughtcrime.securesms.conversation.ConversationMessage;
import org.thoughtcrime.securesms.database.model.InMemoryMessageRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
import org.thoughtcrime.securesms.giph.mp4.GiphyMp4Playable;
@ -75,6 +76,7 @@ public interface BindableConversationItem extends Unbindable, GiphyMp4Playable {
void onInviteFriendsToGroupClicked(@NonNull GroupId.V2 groupId);
void onEnableCallNotificationsClicked();
void onPlayInlineContent(ConversationMessage conversationMessage);
void onInMemoryMessageClicked(@NonNull InMemoryMessageRecord messageRecord);
/** @return true if handled, false if you want to let the normal url handling continue */
boolean onUrlClicked(@NonNull String url);

Wyświetl plik

@ -1,35 +1,37 @@
package org.thoughtcrime.securesms.conversation;
import androidx.annotation.NonNull;
/**
* Represents metadata about a conversation.
*/
final class ConversationData {
private final long threadId;
private final long lastSeen;
private final int lastSeenPosition;
private final int lastScrolledPosition;
private final boolean hasSent;
private final boolean isMessageRequestAccepted;
private final int jumpToPosition;
private final int threadSize;
private final long threadId;
private final long lastSeen;
private final int lastSeenPosition;
private final int lastScrolledPosition;
private final boolean hasSent;
private final int jumpToPosition;
private final int threadSize;
private final MessageRequestData messageRequestData;
ConversationData(long threadId,
long lastSeen,
int lastSeenPosition,
int lastScrolledPosition,
boolean hasSent,
boolean isMessageRequestAccepted,
int jumpToPosition,
int threadSize)
int threadSize,
@NonNull MessageRequestData messageRequestData)
{
this.threadId = threadId;
this.lastSeen = lastSeen;
this.lastSeenPosition = lastSeenPosition;
this.lastScrolledPosition = lastScrolledPosition;
this.hasSent = hasSent;
this.isMessageRequestAccepted = isMessageRequestAccepted;
this.jumpToPosition = jumpToPosition;
this.threadSize = threadSize;
this.threadId = threadId;
this.lastSeen = lastSeen;
this.lastSeenPosition = lastSeenPosition;
this.lastScrolledPosition = lastScrolledPosition;
this.hasSent = hasSent;
this.jumpToPosition = jumpToPosition;
this.threadSize = threadSize;
this.messageRequestData = messageRequestData;
}
public long getThreadId() {
@ -52,10 +54,6 @@ final class ConversationData {
return hasSent;
}
boolean isMessageRequestAccepted() {
return isMessageRequestAccepted;
}
boolean shouldJumpToMessage() {
return jumpToPosition >= 0;
}
@ -71,4 +69,37 @@ final class ConversationData {
int getThreadSize() {
return threadSize;
}
@NonNull MessageRequestData getMessageRequestData() {
return messageRequestData;
}
static final class MessageRequestData {
private final boolean messageRequestAccepted;
private final boolean groupsInCommon;
private final boolean isGroup;
public MessageRequestData(boolean messageRequestAccepted) {
this(messageRequestAccepted, false, false);
}
public MessageRequestData(boolean messageRequestAccepted, boolean groupsInCommon, boolean isGroup) {
this.messageRequestAccepted = messageRequestAccepted;
this.groupsInCommon = groupsInCommon;
this.isGroup = isGroup;
}
public boolean isMessageRequestAccepted() {
return messageRequestAccepted;
}
public boolean includeWarningUpdateMessage() {
return !messageRequestAccepted && !groupsInCommon;
}
public boolean isGroup() {
return isGroup;
}
}
}

Wyświetl plik

@ -9,9 +9,11 @@ import com.annimon.stream.Stream;
import org.signal.core.util.logging.Log;
import org.signal.paging.PagedDataSource;
import org.thoughtcrime.securesms.conversation.ConversationData.MessageRequestData;
import org.thoughtcrime.securesms.conversation.ConversationMessage.ConversationMessageFactory;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.model.InMemoryMessageRecord;
import org.thoughtcrime.securesms.database.model.Mention;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.util.Stopwatch;
@ -30,18 +32,20 @@ class ConversationDataSource implements PagedDataSource<ConversationMessage> {
private static final String TAG = Log.tag(ConversationDataSource.class);
private final Context context;
private final long threadId;
private final Context context;
private final long threadId;
private final MessageRequestData messageRequestData;
ConversationDataSource(@NonNull Context context, long threadId) {
this.context = context;
this.threadId = threadId;
ConversationDataSource(@NonNull Context context, long threadId, @NonNull MessageRequestData messageRequestData) {
this.context = context;
this.threadId = threadId;
this.messageRequestData = messageRequestData;
}
@Override
public int size() {
long startTime = System.currentTimeMillis();
int size = DatabaseFactory.getMmsSmsDatabase(context).getConversationCount(threadId);
int size = DatabaseFactory.getMmsSmsDatabase(context).getConversationCount(threadId) + (messageRequestData.includeWarningUpdateMessage() ? 1 : 0);
Log.d(TAG, "size() for thread " + threadId + ": " + (System.currentTimeMillis() - startTime) + " ms");
@ -55,7 +59,7 @@ class ConversationDataSource implements PagedDataSource<ConversationMessage> {
List<MessageRecord> records = new ArrayList<>(length);
MentionHelper mentionHelper = new MentionHelper();
try (MmsSmsDatabase.Reader reader = db.readerFor(db.getConversation(threadId, start, length))) {
try (MmsSmsDatabase.Reader reader = MmsSmsDatabase.readerFor(db.getConversation(threadId, start, length))) {
MessageRecord record;
while ((record = reader.getNext()) != null && !cancellationSignal.isCanceled()) {
records.add(record);
@ -63,6 +67,10 @@ class ConversationDataSource implements PagedDataSource<ConversationMessage> {
}
}
if (messageRequestData.includeWarningUpdateMessage() && (start + length >= size())) {
records.add(new InMemoryMessageRecord.NoGroupsInCommon(threadId, messageRequestData.isGroup()));
}
stopwatch.split("messages");
mentionHelper.fetchMentions(context);

Wyświetl plik

@ -64,6 +64,7 @@ import androidx.recyclerview.widget.RecyclerView.OnScrollListener;
import com.annimon.stream.Collectors;
import com.annimon.stream.Stream;
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.signal.core.util.StreamUtil;
import org.signal.core.util.concurrent.SignalExecutors;
@ -93,6 +94,7 @@ import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessageDatabase;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.model.InMemoryMessageRecord;
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.MmsMessageRecord;
@ -1040,7 +1042,7 @@ public class ConversationFragment extends LoggingFragment {
adapter.setFooterView(conversationBanner);
Runnable afterScroll = () -> {
if (!conversation.isMessageRequestAccepted()) {
if (!conversation.getMessageRequestData().isMessageRequestAccepted()) {
snapToTopDataObserver.requestScrollPosition(adapter.getItemCount() - 1);
}
@ -1065,7 +1067,7 @@ public class ConversationFragment extends LoggingFragment {
getListAdapter().pulseAtPosition(conversation.getJumpToPosition());
})
.submit();
} else if (conversation.isMessageRequestAccepted()) {
} else if (conversation.getMessageRequestData().isMessageRequestAccepted()) {
snapToTopDataObserver.buildScrollPosition(conversation.shouldScrollToLastSeen() ? lastSeenPosition : lastScrolledPosition)
.withOnPerformScroll((layoutManager, position) -> layoutManager.scrollToPositionWithOffset(position, list.getHeight()))
.withOnScrollRequestComplete(afterScroll)
@ -1609,6 +1611,19 @@ public class ConversationFragment extends LoggingFragment {
public void onPlayInlineContent(ConversationMessage conversationMessage) {
getListAdapter().playInlineContent(conversationMessage);
}
@Override
public void onInMemoryMessageClicked(@NonNull InMemoryMessageRecord messageRecord) {
if (messageRecord instanceof InMemoryMessageRecord.NoGroupsInCommon) {
boolean isGroup = ((InMemoryMessageRecord.NoGroupsInCommon) messageRecord).isGroup();
new MaterialAlertDialogBuilder(requireContext(), R.style.Signal_ThemeOverlay_Dialog_Rounded)
.setMessage(isGroup ? R.string.GroupsInCommonMessageRequest__none_of_your_contacts_or_people_you_chat_with_are_in_this_group
: R.string.GroupsInCommonMessageRequest__you_have_no_groups_in_common_with_this_person)
.setNeutralButton(R.string.GroupsInCommonMessageRequest__about_message_requests, (d, w) -> CommunicationActions.openBrowserLink(requireContext(), getString(R.string.GroupsInCommonMessageRequest__support_article)))
.setPositiveButton(R.string.GroupsInCommonMessageRequest__okay, null)
.show();
}
}
}
public void refreshList() {

Wyświetl plik

@ -10,13 +10,16 @@ import androidx.lifecycle.MutableLiveData;
import org.signal.core.util.concurrent.SignalExecutors;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.util.BubbleUtil;
import org.thoughtcrime.securesms.util.ConversationUtil;
import org.whispersystems.libsignal.util.guava.Optional;
import java.util.List;
import java.util.concurrent.Executor;
class ConversationRepository {
@ -51,16 +54,15 @@ class ConversationRepository {
}
private @NonNull ConversationData getConversationDataInternal(long threadId, int jumpToPosition) {
ThreadDatabase.ConversationMetadata metadata = DatabaseFactory.getThreadDatabase(context).getConversationMetadata(threadId);
int threadSize = DatabaseFactory.getMmsSmsDatabase(context).getConversationCount(threadId);
long lastSeen = metadata.getLastSeen();
boolean hasSent = metadata.hasSent();
int lastSeenPosition = 0;
long lastScrolled = metadata.getLastScrolled();
int lastScrolledPosition = 0;
boolean isMessageRequestAccepted = RecipientUtil.isMessageRequestAccepted(context, threadId);
ThreadDatabase.ConversationMetadata metadata = DatabaseFactory.getThreadDatabase(context).getConversationMetadata(threadId);
int threadSize = DatabaseFactory.getMmsSmsDatabase(context).getConversationCount(threadId);
long lastSeen = metadata.getLastSeen();
boolean hasSent = metadata.hasSent();
int lastSeenPosition = 0;
long lastScrolled = metadata.getLastScrolled();
int lastScrolledPosition = 0;
boolean isMessageRequestAccepted = RecipientUtil.isMessageRequestAccepted(context, threadId);
ConversationData.MessageRequestData messageRequestData = new ConversationData.MessageRequestData(isMessageRequestAccepted);
if (lastSeen > 0) {
lastSeenPosition = DatabaseFactory.getMmsSmsDatabase(context).getMessagePositionOnOrAfterTimestamp(threadId, lastSeen);
@ -74,6 +76,28 @@ class ConversationRepository {
lastScrolledPosition = DatabaseFactory.getMmsSmsDatabase(context).getMessagePositionOnOrAfterTimestamp(threadId, lastScrolled);
}
return new ConversationData(threadId, lastSeen, lastSeenPosition, lastScrolledPosition, hasSent, isMessageRequestAccepted, jumpToPosition, threadSize);
if (!isMessageRequestAccepted) {
boolean isGroup = false;
boolean recipientIsKnownOrHasGroupsInCommon = false;
Recipient threadRecipient = DatabaseFactory.getThreadDatabase(context).getRecipientForThreadId(threadId);
if (threadRecipient.isGroup()) {
Optional<GroupDatabase.GroupRecord> group = DatabaseFactory.getGroupDatabase(context).getGroup(threadRecipient.getId());
if (group.isPresent()) {
List<Recipient> recipients = Recipient.resolvedList(group.get().getMembers());
for (Recipient recipient : recipients) {
if ((recipient.isProfileSharing() || recipient.hasGroupsInCommon()) && !recipient.isSelf()) {
recipientIsKnownOrHasGroupsInCommon = true;
break;
}
}
}
isGroup = true;
} else if (threadRecipient.hasGroupsInCommon()) {
recipientIsKnownOrHasGroupsInCommon = true;
}
messageRequestData = new ConversationData.MessageRequestData(isMessageRequestAccepted, recipientIsKnownOrHasGroupsInCommon, isGroup);
}
return new ConversationData(threadId, lastSeen, lastSeenPosition, lastScrolledPosition, hasSent, jumpToPosition, threadSize, messageRequestData);
}
}

Wyświetl plik

@ -27,6 +27,7 @@ import org.thoughtcrime.securesms.VerifyIdentityActivity;
import org.thoughtcrime.securesms.conversation.ui.error.EnableCallNotificationSettingsDialog;
import org.thoughtcrime.securesms.database.IdentityDatabase.IdentityRecord;
import org.thoughtcrime.securesms.database.model.GroupCallUpdateDetailsUtil;
import org.thoughtcrime.securesms.database.model.InMemoryMessageRecord;
import org.thoughtcrime.securesms.database.model.LiveUpdateMessage;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.database.model.UpdateDescription;
@ -340,6 +341,15 @@ public final class ConversationUpdateItem extends FrameLayout
eventListener.onEnableCallNotificationsClicked();
}
});
} else if (conversationMessage.getMessageRecord().isInMemoryMessageRecord() && ((InMemoryMessageRecord) conversationMessage.getMessageRecord()).showActionButton()) {
InMemoryMessageRecord inMemoryMessageRecord = (InMemoryMessageRecord) conversationMessage.getMessageRecord();
actionButton.setVisibility(VISIBLE);
actionButton.setText(inMemoryMessageRecord.getActionButtonText());
actionButton.setOnClickListener(v -> {
if (eventListener != null) {
eventListener.onInMemoryMessageClicked(inMemoryMessageRecord);
}
});
} else {
actionButton.setVisibility(GONE);
actionButton.setOnClickListener(null);

Wyświetl plik

@ -21,7 +21,6 @@ import org.thoughtcrime.securesms.mediasend.Media;
import org.thoughtcrime.securesms.mediasend.MediaRepository;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import org.thoughtcrime.securesms.wallpaper.ChatWallpaper;
import org.whispersystems.libsignal.util.Pair;
@ -72,12 +71,14 @@ class ConversationViewModel extends ViewModel {
});
LiveData<Pair<Long, PagedData<ConversationMessage>>> pagedDataForThreadId = Transformations.map(metadata, data -> {
final int startPosition;
int startPosition;
ConversationData.MessageRequestData messageRequestData = data.getMessageRequestData();
if (data.shouldJumpToMessage()) {
startPosition = data.getJumpToPosition();
} else if (data.isMessageRequestAccepted() && data.shouldScrollToLastSeen()) {
} else if (messageRequestData.isMessageRequestAccepted() && data.shouldScrollToLastSeen()) {
startPosition = data.getLastSeenPosition();
} else if (data.isMessageRequestAccepted()) {
} else if (messageRequestData.isMessageRequestAccepted()) {
startPosition = data.getLastScrolledPosition();
} else {
startPosition = data.getThreadSize();
@ -86,7 +87,7 @@ class ConversationViewModel extends ViewModel {
ApplicationDependencies.getDatabaseObserver().unregisterObserver(messageObserver);
ApplicationDependencies.getDatabaseObserver().registerConversationObserver(data.getThreadId(), messageObserver);
ConversationDataSource dataSource = new ConversationDataSource(context, data.getThreadId());
ConversationDataSource dataSource = new ConversationDataSource(context, data.getThreadId(), messageRequestData);
PagingConfig config = new PagingConfig.Builder()
.setPageSize(25)
.setBufferPages(3)

Wyświetl plik

@ -0,0 +1,111 @@
package org.thoughtcrime.securesms.database.model;
import android.content.Context;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.recipients.Recipient;
import java.util.Collections;
/**
* In memory message record for use in temporary conversation messages.
*/
public class InMemoryMessageRecord extends MessageRecord {
private InMemoryMessageRecord(long id,
String body,
Recipient conversationRecipient,
long threadId,
long type)
{
super(id,
body,
conversationRecipient,
conversationRecipient,
1,
System.currentTimeMillis(),
System.currentTimeMillis(),
System.currentTimeMillis(),
threadId,
0,
0,
type,
Collections.emptyList(),
Collections.emptyList(),
-1,
0,
System.currentTimeMillis(),
0,
false,
Collections.emptyList(),
false,
0,
0);
}
@Override
public boolean isMms() {
return false;
}
@Override
public boolean isMmsNotification() {
return false;
}
@Override
public boolean isInMemoryMessageRecord() {
return true;
}
public boolean showActionButton() {
return false;
}
public @StringRes int getActionButtonText() {
return 0;
}
/**
* Warning message to show during message request state if you do not have groups in common
* with an individual or do not know anyone in the group.
*/
public static final class NoGroupsInCommon extends InMemoryMessageRecord {
private final boolean isGroup;
public NoGroupsInCommon(long threadId, boolean isGroup) {
super(-1, "", Recipient.UNKNOWN, threadId, 0);
this.isGroup = isGroup;
}
@Override
public @Nullable UpdateDescription getUpdateDisplayBody(@NonNull Context context) {
return UpdateDescription.staticDescription(context.getString(isGroup ? R.string.ConversationUpdateItem_no_contacts_in_this_group_review_requests_carefully
: R.string.ConversationUpdateItem_no_groups_in_common_review_requests_carefully),
R.drawable.ic_update_info_16);
}
@Override
public boolean isUpdate() {
return true;
}
@Override
public boolean showActionButton() {
return true;
}
public boolean isGroup() {
return isGroup;
}
@Override
public @StringRes int getActionButtonText() {
return R.string.ConversationUpdateItem_learn_more;
}
}
}

Wyświetl plik

@ -489,6 +489,10 @@ public abstract class MessageRecord extends DisplayRecord {
return MmsSmsColumns.Types.isFailedDecryptType(type);
}
public boolean isInMemoryMessageRecord() {
return false;
}
protected static SpannableString emphasisAdded(String sequence) {
SpannableString spannable = new SpannableString(sequence);
spannable.setSpan(new RelativeSizeSpan(0.9f), 0, sequence.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);

Wyświetl plik

@ -117,7 +117,7 @@
<style name="Signal.ThemeOverlay.Dialog.Rounded" parent="ThemeOverlay.MaterialComponents.MaterialAlertDialog">
<item name="alertDialogStyle">@style/Signal.MaterialAlertDialog</item>
<item name="android:background">@color/signal_background_dialog</item>
<item name="android:textColorPrimary">@color/signal_text_primary_dialog</item>
<item name="materialAlertDialogBodyTextStyle">@style/Signal.Text.Body</item>
<item name="buttonBarPositiveButtonStyle">@style/Signal.Widget.Button.Dialog</item>
<item name="buttonBarNeutralButtonStyle">@style/Signal.Widget.Button.Dialog</item>
<item name="buttonBarNegativeButtonStyle">@style/Signal.Widget.Button.Dialog</item>

Wyświetl plik

@ -1880,6 +1880,8 @@
<string name="ConversationUpdateItem_call_is_full">Call is full</string>
<string name="ConversationUpdateItem_invite_friends">Invite friends</string>
<string name="ConversationUpdateItem_enable_call_notifications">Enable Call Notifications</string>
<string name="ConversationUpdateItem_no_groups_in_common_review_requests_carefully">No groups in common. Review requests carefully.</string>
<string name="ConversationUpdateItem_no_contacts_in_this_group_review_requests_carefully">No contacts in this group. Review requests carefully.</string>
<!-- audio_view -->
<string name="audio_view__play_pause_accessibility_description">Play … Pause</string>
@ -3337,6 +3339,13 @@
<string name="CanNotSendPaymentDialog__to_send_a_payment_to_this_user">To send a payment to this user they need to accept a message request from you. Send them a message to create a message request.</string>
<string name="CanNotSendPaymentDialog__send_a_message">Send a message</string>
<!-- GroupsInCommonMessageRequest -->
<string name="GroupsInCommonMessageRequest__you_have_no_groups_in_common_with_this_person">You have no groups in common with this person. Review requests carefully before accepting to avoid unwanted messages.</string>
<string name="GroupsInCommonMessageRequest__none_of_your_contacts_or_people_you_chat_with_are_in_this_group">None of your contacts or people you chat with are in this group. Review requests carefully before accepting to avoid unwanted messages.</string>
<string name="GroupsInCommonMessageRequest__about_message_requests">About message requests</string>
<string name="GroupsInCommonMessageRequest__okay">Okay</string>
<string name="GroupsInCommonMessageRequest__support_article" translatable="false">https://support.signal.org/hc/articles/360007459591</string>
<!-- EOF -->
</resources>