mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-25 19:29:54 +01:00
Add universal disappearing messages.
This commit is contained in:
committed by
Greyson Parrelli
parent
8c6a88374b
commit
defd5e8047
@@ -2412,6 +2412,17 @@ public class ConversationActivity extends PassphraseRequiredActivity
|
||||
if (groupCallViewModel != null) {
|
||||
groupCallViewModel.onRecipientChange(recipient);
|
||||
}
|
||||
|
||||
if (this.threadId == -1) {
|
||||
SimpleTask.run(() -> DatabaseFactory.getThreadDatabase(this).getThreadIdIfExistsFor(recipient.getId()), threadId -> {
|
||||
if (this.threadId != threadId) {
|
||||
Log.d(TAG, "Thread id changed via recipient change");
|
||||
this.threadId = threadId;
|
||||
fragment.reload(recipient, this.threadId);
|
||||
setVisibleThread(this.threadId);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||
|
||||
@@ -50,6 +50,7 @@ import org.thoughtcrime.securesms.giph.mp4.GiphyMp4PlaybackPolicyEnforcer;
|
||||
import org.thoughtcrime.securesms.giph.mp4.GiphyMp4Projection;
|
||||
import org.thoughtcrime.securesms.mms.GlideRequests;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.util.CachedInflater;
|
||||
import org.thoughtcrime.securesms.util.DateUtils;
|
||||
import org.thoughtcrime.securesms.util.StickyHeaderDecoration;
|
||||
@@ -374,6 +375,10 @@ public class ConversationAdapter
|
||||
this.pagingController = pagingController;
|
||||
}
|
||||
|
||||
public boolean isForRecipientId(@NonNull RecipientId recipientId) {
|
||||
return recipient.getId().equals(recipientId);
|
||||
}
|
||||
|
||||
void onBindLastSeenViewHolder(StickyHeaderViewHolder viewHolder, int position) {
|
||||
viewHolder.setText(viewHolder.itemView.getContext().getResources().getQuantityString(R.plurals.ConversationAdapter_n_unread_messages, (position + 1), (position + 1)));
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ final class ConversationData {
|
||||
private final int jumpToPosition;
|
||||
private final int threadSize;
|
||||
private final MessageRequestData messageRequestData;
|
||||
private final boolean showUniversalExpireTimerMessage;
|
||||
|
||||
ConversationData(long threadId,
|
||||
long lastSeen,
|
||||
@@ -22,16 +23,18 @@ final class ConversationData {
|
||||
boolean hasSent,
|
||||
int jumpToPosition,
|
||||
int threadSize,
|
||||
@NonNull MessageRequestData messageRequestData)
|
||||
@NonNull MessageRequestData messageRequestData,
|
||||
boolean showUniversalExpireTimerMessage)
|
||||
{
|
||||
this.threadId = threadId;
|
||||
this.lastSeen = lastSeen;
|
||||
this.lastSeenPosition = lastSeenPosition;
|
||||
this.lastScrolledPosition = lastScrolledPosition;
|
||||
this.hasSent = hasSent;
|
||||
this.jumpToPosition = jumpToPosition;
|
||||
this.threadSize = threadSize;
|
||||
this.messageRequestData = messageRequestData;
|
||||
this.threadId = threadId;
|
||||
this.lastSeen = lastSeen;
|
||||
this.lastSeenPosition = lastSeenPosition;
|
||||
this.lastScrolledPosition = lastScrolledPosition;
|
||||
this.hasSent = hasSent;
|
||||
this.jumpToPosition = jumpToPosition;
|
||||
this.threadSize = threadSize;
|
||||
this.messageRequestData = messageRequestData;
|
||||
this.showUniversalExpireTimerMessage = showUniversalExpireTimerMessage;
|
||||
}
|
||||
|
||||
public long getThreadId() {
|
||||
@@ -74,6 +77,10 @@ final class ConversationData {
|
||||
return messageRequestData;
|
||||
}
|
||||
|
||||
public boolean showUniversalExpireTimerMessage() {
|
||||
return showUniversalExpireTimerMessage;
|
||||
}
|
||||
|
||||
static final class MessageRequestData {
|
||||
|
||||
private final boolean messageRequestAccepted;
|
||||
|
||||
@@ -35,17 +35,21 @@ class ConversationDataSource implements PagedDataSource<ConversationMessage> {
|
||||
private final Context context;
|
||||
private final long threadId;
|
||||
private final MessageRequestData messageRequestData;
|
||||
private final boolean showUniversalExpireTimerUpdate;
|
||||
|
||||
ConversationDataSource(@NonNull Context context, long threadId, @NonNull MessageRequestData messageRequestData) {
|
||||
this.context = context;
|
||||
this.threadId = threadId;
|
||||
this.messageRequestData = messageRequestData;
|
||||
ConversationDataSource(@NonNull Context context, long threadId, @NonNull MessageRequestData messageRequestData, boolean showUniversalExpireTimerUpdate) {
|
||||
this.context = context;
|
||||
this.threadId = threadId;
|
||||
this.messageRequestData = messageRequestData;
|
||||
this.showUniversalExpireTimerUpdate = showUniversalExpireTimerUpdate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
long startTime = System.currentTimeMillis();
|
||||
int size = DatabaseFactory.getMmsSmsDatabase(context).getConversationCount(threadId) + (messageRequestData.includeWarningUpdateMessage() ? 1 : 0);
|
||||
int size = DatabaseFactory.getMmsSmsDatabase(context).getConversationCount(threadId) +
|
||||
(messageRequestData.includeWarningUpdateMessage() ? 1 : 0) +
|
||||
(showUniversalExpireTimerUpdate ? 1 : 0);
|
||||
|
||||
Log.d(TAG, "size() for thread " + threadId + ": " + (System.currentTimeMillis() - startTime) + " ms");
|
||||
|
||||
@@ -71,6 +75,10 @@ class ConversationDataSource implements PagedDataSource<ConversationMessage> {
|
||||
records.add(new InMemoryMessageRecord.NoGroupsInCommon(threadId, messageRequestData.isGroup()));
|
||||
}
|
||||
|
||||
if (showUniversalExpireTimerUpdate) {
|
||||
records.add(new InMemoryMessageRecord.UniversalExpireTimerUpdate(threadId));
|
||||
}
|
||||
|
||||
stopwatch.split("messages");
|
||||
|
||||
mentionHelper.fetchMentions(context);
|
||||
|
||||
@@ -183,38 +183,37 @@ public class ConversationFragment extends LoggingFragment {
|
||||
|
||||
private ConversationFragmentListener listener;
|
||||
|
||||
private LiveRecipient recipient;
|
||||
private long threadId;
|
||||
private boolean isReacting;
|
||||
private ActionMode actionMode;
|
||||
private Locale locale;
|
||||
private FrameLayout videoContainer;
|
||||
private RecyclerView list;
|
||||
private RecyclerView.ItemDecoration lastSeenDecoration;
|
||||
private RecyclerView.ItemDecoration inlineDateDecoration;
|
||||
private ViewSwitcher topLoadMoreView;
|
||||
private ViewSwitcher bottomLoadMoreView;
|
||||
private ConversationTypingView typingView;
|
||||
private View composeDivider;
|
||||
private ConversationScrollToView scrollToBottomButton;
|
||||
private ConversationScrollToView scrollToMentionButton;
|
||||
private TextView scrollDateHeader;
|
||||
private ConversationBannerView conversationBanner;
|
||||
private ConversationBannerView emptyConversationBanner;
|
||||
private MessageRequestViewModel messageRequestViewModel;
|
||||
private MessageCountsViewModel messageCountsViewModel;
|
||||
private ConversationViewModel conversationViewModel;
|
||||
private SnapToTopDataObserver snapToTopDataObserver;
|
||||
private MarkReadHelper markReadHelper;
|
||||
private Animation scrollButtonInAnimation;
|
||||
private Animation mentionButtonInAnimation;
|
||||
private Animation scrollButtonOutAnimation;
|
||||
private Animation mentionButtonOutAnimation;
|
||||
private OnScrollListener conversationScrollListener;
|
||||
private int pulsePosition = -1;
|
||||
private VoiceNoteMediaController voiceNoteMediaController;
|
||||
private View toolbarShadow;
|
||||
private Stopwatch startupStopwatch;
|
||||
private LiveRecipient recipient;
|
||||
private long threadId;
|
||||
private boolean isReacting;
|
||||
private ActionMode actionMode;
|
||||
private Locale locale;
|
||||
private FrameLayout videoContainer;
|
||||
private RecyclerView list;
|
||||
private RecyclerView.ItemDecoration lastSeenDecoration;
|
||||
private RecyclerView.ItemDecoration inlineDateDecoration;
|
||||
private ViewSwitcher topLoadMoreView;
|
||||
private ViewSwitcher bottomLoadMoreView;
|
||||
private ConversationTypingView typingView;
|
||||
private View composeDivider;
|
||||
private ConversationScrollToView scrollToBottomButton;
|
||||
private ConversationScrollToView scrollToMentionButton;
|
||||
private TextView scrollDateHeader;
|
||||
private ConversationBannerView conversationBanner;
|
||||
private MessageRequestViewModel messageRequestViewModel;
|
||||
private MessageCountsViewModel messageCountsViewModel;
|
||||
private ConversationViewModel conversationViewModel;
|
||||
private SnapToTopDataObserver snapToTopDataObserver;
|
||||
private MarkReadHelper markReadHelper;
|
||||
private Animation scrollButtonInAnimation;
|
||||
private Animation mentionButtonInAnimation;
|
||||
private Animation scrollButtonOutAnimation;
|
||||
private Animation mentionButtonOutAnimation;
|
||||
private OnScrollListener conversationScrollListener;
|
||||
private int pulsePosition = -1;
|
||||
private VoiceNoteMediaController voiceNoteMediaController;
|
||||
private View toolbarShadow;
|
||||
private Stopwatch startupStopwatch;
|
||||
|
||||
private GiphyMp4ProjectionRecycler giphyMp4ProjectionRecycler;
|
||||
|
||||
@@ -240,15 +239,14 @@ public class ConversationFragment extends LoggingFragment {
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle bundle) {
|
||||
final View view = inflater.inflate(R.layout.conversation_fragment, container, false);
|
||||
videoContainer = view.findViewById(R.id.video_container);
|
||||
list = view.findViewById(android.R.id.list);
|
||||
composeDivider = view.findViewById(R.id.compose_divider);
|
||||
videoContainer = view.findViewById(R.id.video_container);
|
||||
list = view.findViewById(android.R.id.list);
|
||||
composeDivider = view.findViewById(R.id.compose_divider);
|
||||
|
||||
scrollToBottomButton = view.findViewById(R.id.scroll_to_bottom);
|
||||
scrollToMentionButton = view.findViewById(R.id.scroll_to_mention);
|
||||
scrollDateHeader = view.findViewById(R.id.scroll_date_header);
|
||||
emptyConversationBanner = view.findViewById(R.id.empty_conversation_banner);
|
||||
toolbarShadow = requireActivity().findViewById(R.id.conversation_toolbar_shadow);
|
||||
scrollToBottomButton = view.findViewById(R.id.scroll_to_bottom);
|
||||
scrollToMentionButton = view.findViewById(R.id.scroll_to_mention);
|
||||
scrollDateHeader = view.findViewById(R.id.scroll_date_header);
|
||||
toolbarShadow = requireActivity().findViewById(R.id.conversation_toolbar_shadow);
|
||||
|
||||
final LinearLayoutManager layoutManager = new SmoothScrollingLinearLayoutManager(getActivity(), true);
|
||||
list.setHasFixedSize(false);
|
||||
@@ -483,7 +481,6 @@ public class ConversationFragment extends LoggingFragment {
|
||||
|
||||
messageRequestViewModel.getRecipientInfo().observe(getViewLifecycleOwner(), recipientInfo -> {
|
||||
presentMessageRequestProfileView(requireContext(), recipientInfo, conversationBanner);
|
||||
presentMessageRequestProfileView(requireContext(), recipientInfo, emptyConversationBanner);
|
||||
});
|
||||
|
||||
messageRequestViewModel.getMessageData().observe(getViewLifecycleOwner(), data -> {
|
||||
@@ -606,7 +603,16 @@ public class ConversationFragment extends LoggingFragment {
|
||||
}
|
||||
|
||||
private void initializeListAdapter() {
|
||||
if (this.recipient != null && this.threadId != -1) {
|
||||
if (threadId == -1) {
|
||||
toolbarShadow.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (this.recipient != null) {
|
||||
if (getListAdapter() != null && getListAdapter().isForRecipientId(this.recipient.getId())) {
|
||||
Log.d(TAG, "List adapter already initialized for " + this.recipient.getId());
|
||||
return;
|
||||
}
|
||||
|
||||
Log.d(TAG, "Initializing adapter for " + recipient.getId());
|
||||
ConversationAdapter adapter = new ConversationAdapter(this, GlideApp.with(this), locale, selectionClickListener, this.recipient.get(), new AttachmentMediaSourceFactory(requireContext()));
|
||||
adapter.setPagingController(conversationViewModel.getPagingController());
|
||||
@@ -618,8 +624,6 @@ public class ConversationFragment extends LoggingFragment {
|
||||
|
||||
setLastSeen(conversationViewModel.getLastSeen());
|
||||
|
||||
emptyConversationBanner.setVisibility(View.GONE);
|
||||
|
||||
adapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {
|
||||
@Override
|
||||
public void onItemRangeInserted(int positionStart, int itemCount) {
|
||||
@@ -631,9 +635,6 @@ public class ConversationFragment extends LoggingFragment {
|
||||
});
|
||||
}
|
||||
});
|
||||
} else if (threadId == -1) {
|
||||
emptyConversationBanner.setVisibility(View.VISIBLE);
|
||||
toolbarShadow.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -726,6 +727,7 @@ public class ConversationFragment extends LoggingFragment {
|
||||
menu.findItem(R.id.menu_context_save_attachment).setVisible(menuState.shouldShowSaveAttachmentAction());
|
||||
menu.findItem(R.id.menu_context_resend).setVisible(menuState.shouldShowResendAction());
|
||||
menu.findItem(R.id.menu_context_copy).setVisible(menuState.shouldShowCopyAction());
|
||||
menu.findItem(R.id.menu_context_delete_message).setVisible(menuState.shouldShowDeleteAction());
|
||||
}
|
||||
|
||||
private @Nullable ConversationAdapter getListAdapter() {
|
||||
@@ -756,7 +758,9 @@ public class ConversationFragment extends LoggingFragment {
|
||||
snapToTopDataObserver.requestScrollPosition(0);
|
||||
conversationViewModel.onConversationDataAvailable(recipient.getId(), threadId, -1);
|
||||
messageCountsViewModel.setThreadId(threadId);
|
||||
markReadHelper = new MarkReadHelper(threadId, requireContext());
|
||||
initializeListAdapter();
|
||||
initializeTypingObserver();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1229,7 +1233,6 @@ public class ConversationFragment extends LoggingFragment {
|
||||
toolbar.getGlobalVisibleRect(rect);
|
||||
ViewUtil.setTopMargin(scrollDateHeader, rect.bottom + ViewUtil.dpToPx(8));
|
||||
ViewUtil.setTopMargin(conversationBanner, rect.bottom + ViewUtil.dpToPx(16));
|
||||
ViewUtil.setTopMargin(emptyConversationBanner, rect.bottom + ViewUtil.dpToPx(16));
|
||||
toolbar.getViewTreeObserver().removeOnGlobalLayoutListener(this);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -13,6 +13,7 @@ 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.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientUtil;
|
||||
import org.thoughtcrime.securesms.util.BubbleUtil;
|
||||
@@ -32,11 +33,11 @@ class ConversationRepository {
|
||||
this.executor = SignalExecutors.BOUNDED;
|
||||
}
|
||||
|
||||
LiveData<ConversationData> getConversationData(long threadId, int jumpToPosition) {
|
||||
LiveData<ConversationData> getConversationData(long threadId, @NonNull Recipient recipient, int jumpToPosition) {
|
||||
MutableLiveData<ConversationData> liveData = new MutableLiveData<>();
|
||||
|
||||
executor.execute(() -> {
|
||||
liveData.postValue(getConversationDataInternal(threadId, jumpToPosition));
|
||||
liveData.postValue(getConversationDataInternal(threadId, recipient, jumpToPosition));
|
||||
});
|
||||
|
||||
return liveData;
|
||||
@@ -53,16 +54,17 @@ 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);
|
||||
ConversationData.MessageRequestData messageRequestData = new ConversationData.MessageRequestData(isMessageRequestAccepted);
|
||||
private @NonNull ConversationData getConversationDataInternal(long threadId, @NonNull Recipient conversationRecipient, 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);
|
||||
ConversationData.MessageRequestData messageRequestData = new ConversationData.MessageRequestData(isMessageRequestAccepted);
|
||||
boolean showUniversalExpireTimerUpdate = false;
|
||||
|
||||
if (lastSeen > 0) {
|
||||
lastSeenPosition = DatabaseFactory.getMmsSmsDatabase(context).getMessagePositionOnOrAfterTimestamp(threadId, lastSeen);
|
||||
@@ -79,9 +81,8 @@ class ConversationRepository {
|
||||
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 (conversationRecipient.isGroup()) {
|
||||
Optional<GroupDatabase.GroupRecord> group = DatabaseFactory.getGroupDatabase(context).getGroup(conversationRecipient.getId());
|
||||
if (group.isPresent()) {
|
||||
List<Recipient> recipients = Recipient.resolvedList(group.get().getMembers());
|
||||
for (Recipient recipient : recipients) {
|
||||
@@ -92,12 +93,20 @@ class ConversationRepository {
|
||||
}
|
||||
}
|
||||
isGroup = true;
|
||||
} else if (threadRecipient.hasGroupsInCommon()) {
|
||||
} else if (conversationRecipient.hasGroupsInCommon()) {
|
||||
recipientIsKnownOrHasGroupsInCommon = true;
|
||||
}
|
||||
messageRequestData = new ConversationData.MessageRequestData(isMessageRequestAccepted, recipientIsKnownOrHasGroupsInCommon, isGroup);
|
||||
}
|
||||
|
||||
return new ConversationData(threadId, lastSeen, lastSeenPosition, lastScrolledPosition, hasSent, jumpToPosition, threadSize, messageRequestData);
|
||||
if (SignalStore.settings().getUniversalExpireTimer() != 0 &&
|
||||
conversationRecipient.getExpireMessages() == 0 &&
|
||||
!conversationRecipient.isGroup() &&
|
||||
(threadId == -1 || !DatabaseFactory.getMmsSmsDatabase(context).hasMeaningfulMessage(threadId)))
|
||||
{
|
||||
showUniversalExpireTimerUpdate = true;
|
||||
}
|
||||
|
||||
return new ConversationData(threadId, lastSeen, lastSeenPosition, lastScrolledPosition, hasSent, jumpToPosition, threadSize, messageRequestData, showUniversalExpireTimerUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,8 +69,11 @@ public class ConversationViewModel extends ViewModel {
|
||||
this.pagingController = new ProxyPagingController();
|
||||
this.messageObserver = pagingController::onDataInvalidated;
|
||||
|
||||
LiveData<ConversationData> metadata = Transformations.switchMap(threadId, thread -> {
|
||||
LiveData<ConversationData> conversationData = conversationRepository.getConversationData(thread, jumpToPosition);
|
||||
LiveData<Recipient> recipientLiveData = LiveDataUtil.mapAsync(recipientId, Recipient::resolved);
|
||||
LiveData<ThreadAndRecipient> threadAndRecipient = LiveDataUtil.combineLatest(threadId, recipientLiveData, ThreadAndRecipient::new);
|
||||
|
||||
LiveData<ConversationData> metadata = Transformations.switchMap(threadAndRecipient, d -> {
|
||||
LiveData<ConversationData> conversationData = conversationRepository.getConversationData(d.threadId, d.recipient, jumpToPosition);
|
||||
|
||||
jumpToPosition = -1;
|
||||
|
||||
@@ -94,12 +97,11 @@ public class ConversationViewModel extends ViewModel {
|
||||
ApplicationDependencies.getDatabaseObserver().unregisterObserver(messageObserver);
|
||||
ApplicationDependencies.getDatabaseObserver().registerConversationObserver(data.getThreadId(), messageObserver);
|
||||
|
||||
ConversationDataSource dataSource = new ConversationDataSource(context, data.getThreadId(), messageRequestData);
|
||||
PagingConfig config = new PagingConfig.Builder()
|
||||
.setPageSize(25)
|
||||
.setBufferPages(3)
|
||||
.setStartIndex(Math.max(startPosition, 0))
|
||||
.build();
|
||||
ConversationDataSource dataSource = new ConversationDataSource(context, data.getThreadId(), messageRequestData, data.showUniversalExpireTimerMessage());
|
||||
PagingConfig config = new PagingConfig.Builder().setPageSize(25)
|
||||
.setBufferPages(3)
|
||||
.setStartIndex(Math.max(startPosition, 0))
|
||||
.build();
|
||||
|
||||
Log.d(TAG, "Starting at position: " + startPosition + " || jumpToPosition: " + data.getJumpToPosition() + ", lastSeenPosition: " + data.getLastSeenPosition() + ", lastScrolledPosition: " + data.getLastScrolledPosition());
|
||||
return new Pair<>(data.getThreadId(), PagedData.create(dataSource, config));
|
||||
@@ -213,9 +215,20 @@ public class ConversationViewModel extends ViewModel {
|
||||
SHOW_RECAPTCHA
|
||||
}
|
||||
|
||||
private static class ThreadAndRecipient {
|
||||
|
||||
private final long threadId;
|
||||
private final Recipient recipient;
|
||||
|
||||
public ThreadAndRecipient(long threadId, Recipient recipient) {
|
||||
this.threadId = threadId;
|
||||
this.recipient = recipient;
|
||||
}
|
||||
}
|
||||
|
||||
static class Factory extends ViewModelProvider.NewInstanceFactory {
|
||||
@Override
|
||||
public @NonNull<T extends ViewModel> T create(@NonNull Class<T> modelClass) {
|
||||
public @NonNull <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
|
||||
//noinspection ConstantConditions
|
||||
return modelClass.cast(new ConversationViewModel());
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@ final class MenuState {
|
||||
private final boolean saveAttachment;
|
||||
private final boolean resend;
|
||||
private final boolean copy;
|
||||
private final boolean delete;
|
||||
|
||||
private MenuState(@NonNull Builder builder) {
|
||||
forward = builder.forward;
|
||||
@@ -25,6 +26,7 @@ final class MenuState {
|
||||
saveAttachment = builder.saveAttachment;
|
||||
resend = builder.resend;
|
||||
copy = builder.copy;
|
||||
delete = builder.delete;
|
||||
}
|
||||
|
||||
boolean shouldShowForwardAction() {
|
||||
@@ -51,6 +53,10 @@ final class MenuState {
|
||||
return copy;
|
||||
}
|
||||
|
||||
boolean shouldShowDeleteAction() {
|
||||
return delete;
|
||||
}
|
||||
|
||||
static MenuState getMenuState(@NonNull Recipient conversationRecipient,
|
||||
@NonNull Set<MessageRecord> messageRecords,
|
||||
boolean shouldShowMessageRequest)
|
||||
@@ -62,11 +68,14 @@ final class MenuState {
|
||||
boolean sharedContact = false;
|
||||
boolean viewOnce = false;
|
||||
boolean remoteDelete = false;
|
||||
boolean hasInMemory = false;
|
||||
|
||||
for (MessageRecord messageRecord : messageRecords) {
|
||||
if (isActionMessage(messageRecord))
|
||||
{
|
||||
if (isActionMessage(messageRecord)) {
|
||||
actionMessage = true;
|
||||
if (messageRecord.isInMemoryMessageRecord()) {
|
||||
hasInMemory = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (messageRecord.getBody().length() > 0) {
|
||||
@@ -109,6 +118,7 @@ final class MenuState {
|
||||
}
|
||||
|
||||
return builder.shouldShowCopyAction(!actionMessage && !remoteDelete && hasText)
|
||||
.shouldShowDeleteAction(!hasInMemory)
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -134,7 +144,8 @@ final class MenuState {
|
||||
messageRecord.isIdentityDefault() ||
|
||||
messageRecord.isProfileChange() ||
|
||||
messageRecord.isGroupV1MigrationEvent() ||
|
||||
messageRecord.isFailedDecryptionType();
|
||||
messageRecord.isFailedDecryptionType() ||
|
||||
messageRecord.isInMemoryMessageRecord();
|
||||
}
|
||||
|
||||
private final static class Builder {
|
||||
@@ -145,6 +156,7 @@ final class MenuState {
|
||||
private boolean saveAttachment;
|
||||
private boolean resend;
|
||||
private boolean copy;
|
||||
private boolean delete;
|
||||
|
||||
@NonNull Builder shouldShowForwardAction(boolean forward) {
|
||||
this.forward = forward;
|
||||
@@ -176,6 +188,11 @@ final class MenuState {
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull Builder shouldShowDeleteAction(boolean delete) {
|
||||
this.delete = delete;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
MenuState build() {
|
||||
return new MenuState(this);
|
||||
|
||||
Reference in New Issue
Block a user