Remove old Message Details.

master
Cody Henthorne 2020-06-16 18:12:14 -04:00 committed by Greyson Parrelli
parent 027453bbd2
commit 1a09e70a04
18 changed files with 208 additions and 1253 deletions

View File

@ -243,12 +243,6 @@
android:theme="@style/TextSecure.LightTheme.Popup"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" />
<activity android:name=".MessageDetailsActivity"
android:label="@string/AndroidManifest__message_details"
android:windowSoftInputMode="stateHidden"
android:launchMode="singleTask"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".messagedetails.MessageDetailsActivity"
android:label="@string/AndroidManifest__message_details"
android:windowSoftInputMode="stateHidden"

View File

@ -1,451 +0,0 @@
/*
* Copyright (C) 2015 Open Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms;
import android.annotation.SuppressLint;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.database.Cursor;
import android.graphics.drawable.ColorDrawable;
import android.os.AsyncTask;
import android.os.Build;
import android.os.Bundle;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.loader.app.LoaderManager.LoaderCallbacks;
import androidx.loader.content.Loader;
import org.thoughtcrime.securesms.conversation.ConversationItem;
import org.thoughtcrime.securesms.database.GroupDatabase;
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
import org.thoughtcrime.securesms.logging.Log;
import android.os.Parcelable;
import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
import android.widget.TextView;
import org.thoughtcrime.securesms.MessageDetailsRecipientAdapter.RecipientDeliveryStatus;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.GroupReceiptDatabase;
import org.thoughtcrime.securesms.database.GroupReceiptDatabase.GroupReceiptInfo;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.loaders.MessageDetailsLoader;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.LiveRecipient;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.sms.MessageSender;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.DynamicDarkActionBarTheme;
import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.ExpirationUtil;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.concurrent.SignalExecutors;
import org.whispersystems.libsignal.util.guava.Optional;
import java.lang.ref.WeakReference;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Locale;
/**
* @author Jake McGinty
*/
public class MessageDetailsActivity extends PassphraseRequiredActionBarActivity implements LoaderCallbacks<Cursor> {
private final static String TAG = MessageDetailsActivity.class.getSimpleName();
public static final String MESSAGE_ID_EXTRA = "message_id";
public static final String THREAD_ID_EXTRA = "thread_id";
public static final String IS_PUSH_GROUP_EXTRA = "is_push_group";
public static final String TYPE_EXTRA = "type";
public static final String RECIPIENT_EXTRA = "recipient_id";
private GlideRequests glideRequests;
private long threadId;
private boolean isPushGroup;
private ConversationItem conversationItem;
private ViewGroup itemParent;
private View metadataContainer;
private View expiresContainer;
private TextView errorText;
private View resendButton;
private TextView sentDate;
private TextView receivedDate;
private TextView expiresInText;
private View receivedContainer;
private TextView transport;
private TextView toFrom;
private ListView recipientsList;
private LayoutInflater inflater;
private DynamicTheme dynamicTheme = new DynamicDarkActionBarTheme();
private DynamicLanguage dynamicLanguage = new DynamicLanguage();
private boolean running;
@Override
protected void onPreCreate() {
dynamicTheme.onCreate(this);
dynamicLanguage.onCreate(this);
}
@Override
public void onCreate(Bundle bundle, boolean ready) {
setContentView(R.layout.message_details_activity);
running = true;
initializeResources();
initializeActionBar();
getSupportLoaderManager().initLoader(0, null, this);
}
@Override
protected void onResume() {
super.onResume();
dynamicTheme.onResume(this);
dynamicLanguage.onResume(this);
assert getSupportActionBar() != null;
getSupportActionBar().setTitle(R.string.AndroidManifest__message_details);
ApplicationDependencies.getMessageNotifier().setVisibleThread(threadId);
}
@Override
protected void onPause() {
super.onPause();
ApplicationDependencies.getMessageNotifier().clearVisibleThread();
}
@Override
protected void onDestroy() {
super.onDestroy();
running = false;
}
private void initializeActionBar() {
assert getSupportActionBar() != null;
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
LiveRecipient recipient = Recipient.live(getIntent().getParcelableExtra(RECIPIENT_EXTRA));
recipient.observe(this, r -> setActionBarColor(r.getColor()));
setActionBarColor(recipient.get().getColor());
}
private void setActionBarColor(MaterialColor color) {
assert getSupportActionBar() != null;
getSupportActionBar().setBackgroundDrawable(new ColorDrawable(color.toActionBarColor(this)));
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getWindow().setStatusBarColor(color.toStatusBarColor(this));
}
}
private void initializeResources() {
inflater = LayoutInflater.from(this);
View header = inflater.inflate(R.layout.message_details_header, recipientsList, false);
threadId = getIntent().getLongExtra(THREAD_ID_EXTRA, -1);
isPushGroup = getIntent().getBooleanExtra(IS_PUSH_GROUP_EXTRA, false);
glideRequests = GlideApp.with(this);
itemParent = header.findViewById(R.id.item_container);
recipientsList = findViewById(R.id.recipients_list);
metadataContainer = header.findViewById(R.id.metadata_container);
errorText = header.findViewById(R.id.error_text);
resendButton = header.findViewById(R.id.resend_button);
sentDate = header.findViewById(R.id.sent_time);
receivedContainer = header.findViewById(R.id.received_container);
receivedDate = header.findViewById(R.id.received_time);
transport = header.findViewById(R.id.transport);
toFrom = header.findViewById(R.id.tofrom);
expiresContainer = header.findViewById(R.id.expires_container);
expiresInText = header.findViewById(R.id.expires_in);
recipientsList.setHeaderDividersEnabled(false);
recipientsList.addHeaderView(header, null, false);
}
private void updateTransport(MessageRecord messageRecord) {
final String transportText;
if (messageRecord.isOutgoing() && messageRecord.isFailed()) {
transportText = "-";
} else if (messageRecord.isPending()) {
transportText = getString(R.string.ConversationFragment_pending);
} else if (messageRecord.isPush()) {
transportText = getString(R.string.ConversationFragment_push);
} else if (messageRecord.isMms()) {
transportText = getString(R.string.ConversationFragment_mms);
} else {
transportText = getString(R.string.ConversationFragment_sms);
}
transport.setText(transportText);
}
private void updateTime(MessageRecord messageRecord) {
sentDate.setOnLongClickListener(null);
receivedDate.setOnLongClickListener(null);
if (messageRecord.isPending() || messageRecord.isFailed()) {
sentDate.setText("-");
receivedContainer.setVisibility(View.GONE);
} else {
Locale dateLocale = dynamicLanguage.getCurrentLocale();
SimpleDateFormat dateFormatter = DateUtils.getDetailedDateFormatter(this, dateLocale);
sentDate.setText(dateFormatter.format(new Date(messageRecord.getDateSent())));
sentDate.setOnLongClickListener(v -> {
copyToClipboard(String.valueOf(messageRecord.getDateSent()));
return true;
});
if (messageRecord.getDateReceived() != messageRecord.getDateSent() && !messageRecord.isOutgoing()) {
receivedDate.setText(dateFormatter.format(new Date(messageRecord.getDateReceived())));
receivedDate.setOnLongClickListener(v -> {
copyToClipboard(String.valueOf(messageRecord.getDateReceived()));
return true;
});
receivedContainer.setVisibility(View.VISIBLE);
} else {
receivedContainer.setVisibility(View.GONE);
}
}
}
private void updateExpirationTime(final MessageRecord messageRecord) {
if (messageRecord.getExpiresIn() <= 0 || messageRecord.getExpireStarted() <= 0) {
expiresContainer.setVisibility(View.GONE);
return;
}
expiresContainer.setVisibility(View.VISIBLE);
Util.runOnMain(new Runnable() {
@Override
public void run() {
long elapsed = System.currentTimeMillis() - messageRecord.getExpireStarted();
long remaining = messageRecord.getExpiresIn() - elapsed;
String duration = ExpirationUtil.getExpirationDisplayValue(MessageDetailsActivity.this, Math.max((int)(remaining / 1000), 1));
expiresInText.setText(duration);
if (running) {
Util.runOnMainDelayed(this, 500);
}
}
});
}
private void updateRecipients(MessageRecord messageRecord, Recipient recipient, List<RecipientDeliveryStatus> recipients) {
final int toFromRes;
if (messageRecord.isMms() && !messageRecord.isPush() && !messageRecord.isOutgoing()) {
toFromRes = R.string.message_details_header__with;
} else if (messageRecord.isOutgoing()) {
toFromRes = R.string.message_details_header__to;
} else {
toFromRes = R.string.message_details_header__from;
}
toFrom.setText(toFromRes);
conversationItem.bind(messageRecord, Optional.absent(), Optional.absent(), glideRequests, dynamicLanguage.getCurrentLocale(), new HashSet<>(), recipient, null, false);
Parcelable state = recipientsList.onSaveInstanceState();
recipientsList.setAdapter(new MessageDetailsRecipientAdapter(this, glideRequests, messageRecord, recipients, isPushGroup));
recipientsList.onRestoreInstanceState(state);
}
private void inflateMessageViewIfAbsent(MessageRecord messageRecord) {
if (conversationItem == null) {
if (messageRecord.isGroupAction()) {
conversationItem = (ConversationItem) inflater.inflate(R.layout.conversation_item_update, itemParent, false);
} else if (messageRecord.isOutgoing()) {
conversationItem = (ConversationItem) inflater.inflate(R.layout.conversation_item_sent_multimedia, itemParent, false);
} else {
conversationItem = (ConversationItem) inflater.inflate(R.layout.conversation_item_received_multimedia, itemParent, false);
}
itemParent.addView(conversationItem);
}
}
private @Nullable MessageRecord getMessageRecord(Context context, Cursor cursor, String type) {
switch (type) {
case MmsSmsDatabase.SMS_TRANSPORT:
SmsDatabase smsDatabase = DatabaseFactory.getSmsDatabase(context);
SmsDatabase.Reader reader = smsDatabase.readerFor(cursor);
return reader.getNext();
case MmsSmsDatabase.MMS_TRANSPORT:
MmsDatabase mmsDatabase = DatabaseFactory.getMmsDatabase(context);
MmsDatabase.Reader mmsReader = mmsDatabase.readerFor(cursor);
return mmsReader.getNext();
default:
throw new AssertionError("no valid message type specified");
}
}
private void copyToClipboard(@NonNull String text) {
((ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE)).setPrimaryClip(ClipData.newPlainText("text", text));
}
@Override
public @NonNull Loader<Cursor> onCreateLoader(int id, Bundle args) {
return new MessageDetailsLoader(this, getIntent().getStringExtra(TYPE_EXTRA),
getIntent().getLongExtra(MESSAGE_ID_EXTRA, -1));
}
@Override
public void onLoadFinished(@NonNull Loader<Cursor> loader, Cursor cursor) {
MessageRecord messageRecord = getMessageRecord(this, cursor, getIntent().getStringExtra(TYPE_EXTRA));
if (messageRecord == null) {
finish();
} else {
new MessageRecipientAsyncTask(this, messageRecord).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
}
@Override
public void onLoaderReset(@NonNull Loader<Cursor> loader) {
recipientsList.setAdapter(null);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
super.onOptionsItemSelected(item);
switch (item.getItemId()) {
case android.R.id.home: finish(); return true;
}
return false;
}
@SuppressLint("StaticFieldLeak")
private class MessageRecipientAsyncTask extends AsyncTask<Void,Void,List<RecipientDeliveryStatus>> {
private final WeakReference<Context> weakContext;
private final MessageRecord messageRecord;
MessageRecipientAsyncTask(@NonNull Context context, @NonNull MessageRecord messageRecord) {
this.weakContext = new WeakReference<>(context);
this.messageRecord = messageRecord;
}
protected Context getContext() {
return weakContext.get();
}
@Override
public List<RecipientDeliveryStatus> doInBackground(Void... voids) {
Context context = getContext();
if (context == null) {
Log.w(TAG, "associated context is destroyed, finishing early");
return null;
}
List<RecipientDeliveryStatus> recipients = new LinkedList<>();
if (!messageRecord.getRecipient().isGroup()) {
recipients.add(new RecipientDeliveryStatus(messageRecord.getRecipient(), getStatusFor(messageRecord.getDeliveryReceiptCount(), messageRecord.getReadReceiptCount(), messageRecord.isPending()), messageRecord.isUnidentified(), -1));
} else {
List<GroupReceiptInfo> receiptInfoList = DatabaseFactory.getGroupReceiptDatabase(context).getGroupReceiptInfo(messageRecord.getId());
if (receiptInfoList.isEmpty()) {
List<Recipient> group = DatabaseFactory.getGroupDatabase(context).getGroupMembers(messageRecord.getRecipient().requireGroupId(), GroupDatabase.MemberSet.FULL_MEMBERS_EXCLUDING_SELF);
for (Recipient recipient : group) {
recipients.add(new RecipientDeliveryStatus(recipient, RecipientDeliveryStatus.Status.UNKNOWN, false, -1));
}
} else {
for (GroupReceiptInfo info : receiptInfoList) {
recipients.add(new RecipientDeliveryStatus(Recipient.resolved(info.getRecipientId()),
getStatusFor(info.getStatus(), messageRecord.isPending(), messageRecord.isFailed()),
info.isUnidentified(),
info.getTimestamp()));
}
}
}
return recipients;
}
@Override
public void onPostExecute(List<RecipientDeliveryStatus> recipients) {
if (getContext() == null) {
Log.w(TAG, "AsyncTask finished with a destroyed context, leaving early.");
return;
}
inflateMessageViewIfAbsent(messageRecord);
updateRecipients(messageRecord, messageRecord.getRecipient(), recipients);
boolean isGroupNetworkFailure = messageRecord.isFailed() && !messageRecord.getNetworkFailures().isEmpty();
boolean isIndividualNetworkFailure = messageRecord.isFailed() && !isPushGroup && messageRecord.getIdentityKeyMismatches().isEmpty();
if (isGroupNetworkFailure || isIndividualNetworkFailure) {
errorText.setVisibility(View.VISIBLE);
resendButton.setVisibility(View.VISIBLE);
resendButton.setOnClickListener(this::onResendClicked);
metadataContainer.setVisibility(View.GONE);
} else if (messageRecord.isFailed()) {
errorText.setVisibility(View.VISIBLE);
resendButton.setVisibility(View.GONE);
resendButton.setOnClickListener(null);
metadataContainer.setVisibility(View.GONE);
} else {
updateTransport(messageRecord);
updateTime(messageRecord);
updateExpirationTime(messageRecord);
errorText.setVisibility(View.GONE);
resendButton.setVisibility(View.GONE);
resendButton.setOnClickListener(null);
metadataContainer.setVisibility(View.VISIBLE);
}
}
private RecipientDeliveryStatus.Status getStatusFor(int deliveryReceiptCount, int readReceiptCount, boolean pending) {
if (readReceiptCount > 0) return RecipientDeliveryStatus.Status.READ;
else if (deliveryReceiptCount > 0) return RecipientDeliveryStatus.Status.DELIVERED;
else if (!pending) return RecipientDeliveryStatus.Status.SENT;
else return RecipientDeliveryStatus.Status.PENDING;
}
private RecipientDeliveryStatus.Status getStatusFor(int groupStatus, boolean pending, boolean failed) {
if (groupStatus == GroupReceiptDatabase.STATUS_READ) return RecipientDeliveryStatus.Status.READ;
else if (groupStatus == GroupReceiptDatabase.STATUS_DELIVERED) return RecipientDeliveryStatus.Status.DELIVERED;
else if (groupStatus == GroupReceiptDatabase.STATUS_UNDELIVERED && failed) return RecipientDeliveryStatus.Status.UNKNOWN;
else if (groupStatus == GroupReceiptDatabase.STATUS_UNDELIVERED && !pending) return RecipientDeliveryStatus.Status.SENT;
else if (groupStatus == GroupReceiptDatabase.STATUS_UNDELIVERED) return RecipientDeliveryStatus.Status.PENDING;
else if (groupStatus == GroupReceiptDatabase.STATUS_UNKNOWN) return RecipientDeliveryStatus.Status.UNKNOWN;
throw new AssertionError();
}
private void onResendClicked(View v) {
resendButton.setVisibility(View.GONE);
SignalExecutors.BOUNDED.execute(() -> MessageSender.resend(MessageDetailsActivity.this, messageRecord));
}
}
}

View File

@ -1,112 +0,0 @@
package org.thoughtcrime.securesms;
import android.content.Context;
import androidx.annotation.NonNull;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AbsListView;
import android.widget.BaseAdapter;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.Conversions;
import org.thoughtcrime.securesms.util.adapter.StableIdGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;
class MessageDetailsRecipientAdapter extends BaseAdapter implements AbsListView.RecyclerListener {
private final Context context;
private final GlideRequests glideRequests;
private final MessageRecord record;
private final List<RecipientDeliveryStatus> members;
private final boolean isPushGroup;
private final StableIdGenerator<RecipientId> idGenerator;
MessageDetailsRecipientAdapter(@NonNull Context context, @NonNull GlideRequests glideRequests,
@NonNull MessageRecord record, @NonNull List<RecipientDeliveryStatus> members,
boolean isPushGroup)
{
this.context = context;
this.glideRequests = glideRequests;
this.record = record;
this.isPushGroup = isPushGroup;
this.members = members;
this.idGenerator = new StableIdGenerator<>();
}
@Override
public int getCount() {
return members.size();
}
@Override
public Object getItem(int position) {
return members.get(position);
}
@Override
public long getItemId(int position) {
return idGenerator.getId(members.get(position).recipient.getId());
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.message_recipient_list_item, parent, false);
}
RecipientDeliveryStatus member = members.get(position);
((MessageRecipientListItem)convertView).set(glideRequests, record, member, isPushGroup);
return convertView;
}
@Override
public void onMovedToScrapHeap(View view) {
((MessageRecipientListItem)view).unbind();
}
static class RecipientDeliveryStatus {
enum Status {
UNKNOWN, PENDING, SENT, DELIVERED, READ
}
private final Recipient recipient;
private final Status deliveryStatus;
private final boolean isUnidentified;
private final long timestamp;
RecipientDeliveryStatus(Recipient recipient, Status deliveryStatus, boolean isUnidentified, long timestamp) {
this.recipient = recipient;
this.deliveryStatus = deliveryStatus;
this.isUnidentified = isUnidentified;
this.timestamp = timestamp;
}
Status getDeliveryStatus() {
return deliveryStatus;
}
boolean isUnidentified() {
return isUnidentified;
}
public long getTimestamp() {
return timestamp;
}
public Recipient getRecipient() {
return recipient;
}
}
}

View File

@ -1,200 +0,0 @@
/*
* Copyright (C) 2014 Open Whisper Systems
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.thoughtcrime.securesms;
import android.content.Context;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.View;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.MessageDetailsRecipientAdapter.RecipientDeliveryStatus;
import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.components.DeliveryStatusView;
import org.thoughtcrime.securesms.components.FromTextView;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.database.documents.NetworkFailure;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientForeverObserver;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
/**
* A simple view to show the recipients of a message
*
* @author Jake McGinty
*/
public class MessageRecipientListItem extends RelativeLayout
implements RecipientForeverObserver
{
@SuppressWarnings("unused")
private final static String TAG = MessageRecipientListItem.class.getSimpleName();
private RecipientDeliveryStatus member;
private GlideRequests glideRequests;
private FromTextView fromView;
private TextView errorDescription;
private TextView actionDescription;
private Button conflictButton;
private AvatarImageView contactPhotoImage;
private ImageView unidentifiedDeliveryIcon;
private DeliveryStatusView deliveryStatusView;
public MessageRecipientListItem(Context context) {
super(context);
}
public MessageRecipientListItem(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
this.fromView = findViewById(R.id.from);
this.errorDescription = findViewById(R.id.error_description);
this.actionDescription = findViewById(R.id.action_description);
this.contactPhotoImage = findViewById(R.id.contact_photo_image);
this.conflictButton = findViewById(R.id.conflict_button);
this.unidentifiedDeliveryIcon = findViewById(R.id.ud_indicator);
this.deliveryStatusView = findViewById(R.id.delivery_status);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
observeMember();
}
@Override
protected void onDetachedFromWindow() {
unsubscribeFromMember();
super.onDetachedFromWindow();
}
public void set(final GlideRequests glideRequests,
final MessageRecord record,
final RecipientDeliveryStatus member,
final boolean isPushGroup)
{
unsubscribeFromMember();
this.glideRequests = glideRequests;
this.member = member;
observeMember();
fromView.setText(member.getRecipient());
contactPhotoImage.setAvatar(glideRequests, member.getRecipient(), false);
setIssueIndicators(record, isPushGroup);
unidentifiedDeliveryIcon.setVisibility(TextSecurePreferences.isShowUnidentifiedDeliveryIndicatorsEnabled(getContext()) && member.isUnidentified() ? VISIBLE : GONE);
}
private void observeMember() {
if (isAttachedToWindow() && member != null && member.getRecipient() != null) {
member.getRecipient().live().observeForever(this);
}
}
private void unsubscribeFromMember() {
if (member != null && member.getRecipient() != null) member.getRecipient().live().removeForeverObserver(this);
}
private void setIssueIndicators(final MessageRecord record,
final boolean isPushGroup)
{
final NetworkFailure networkFailure = getNetworkFailure(record);
final IdentityKeyMismatch keyMismatch = networkFailure == null ? getKeyMismatch(record) : null;
String errorText = "";
if (keyMismatch != null) {
conflictButton.setVisibility(View.VISIBLE);
errorText = getContext().getString(R.string.MessageDetailsRecipient_new_safety_number);
conflictButton.setOnClickListener(v -> new ConfirmIdentityDialog(getContext(), record, keyMismatch).show());
} else if ((networkFailure != null && !record.isPending()) || (!isPushGroup && record.isFailed())) {
conflictButton.setVisibility(View.GONE);
errorText = getContext().getString(R.string.MessageDetailsRecipient_failed_to_send);
} else {
if (record.isOutgoing()) {
if (member.getDeliveryStatus() == RecipientDeliveryStatus.Status.PENDING || member.getDeliveryStatus() == RecipientDeliveryStatus.Status.UNKNOWN) {
deliveryStatusView.setVisibility(View.GONE);
} else if (member.getDeliveryStatus() == RecipientDeliveryStatus.Status.READ) {
deliveryStatusView.setRead();
deliveryStatusView.setVisibility(View.VISIBLE);
} else if (member.getDeliveryStatus() == RecipientDeliveryStatus.Status.DELIVERED) {
deliveryStatusView.setDelivered();
deliveryStatusView.setVisibility(View.VISIBLE);
} else if (member.getDeliveryStatus() == RecipientDeliveryStatus.Status.SENT) {
deliveryStatusView.setSent();
deliveryStatusView.setVisibility(View.VISIBLE);
}
} else {
deliveryStatusView.setVisibility(View.GONE);
}
conflictButton.setVisibility(View.GONE);
}
errorDescription.setText(errorText);
errorDescription.setVisibility(TextUtils.isEmpty(errorText) ? View.GONE : View.VISIBLE);
}
private NetworkFailure getNetworkFailure(final MessageRecord record) {
if (record.hasNetworkFailures()) {
for (final NetworkFailure failure : record.getNetworkFailures()) {
if (failure.getRecipientId(getContext()).equals(member.getRecipient().getId())) {
return failure;
}
}
}
return null;
}
private IdentityKeyMismatch getKeyMismatch(final MessageRecord record) {
if (record.isIdentityMismatchFailure()) {
for (final IdentityKeyMismatch mismatch : record.getIdentityKeyMismatches()) {
if (mismatch.getRecipientId(getContext()).equals(member.getRecipient().getId())) {
return mismatch;
}
}
}
return null;
}
public void unbind() {
unsubscribeFromMember();
}
@Override
public void onRecipientChanged(@NonNull Recipient recipient) {
if (this.member != null && this.member.getRecipient().equals(recipient)) {
Log.d(TAG, "onRecipientChanged -- valid");
fromView.setText(recipient);
contactPhotoImage.setAvatar(glideRequests, recipient, false);
} else {
Log.d(TAG, "onRecipientChanged -- invalid");
}
}
}

View File

@ -60,7 +60,6 @@ import com.annimon.stream.Stream;
import com.google.android.collect.Sets;
import org.thoughtcrime.securesms.ApplicationContext;
import org.thoughtcrime.securesms.MessageDetailsActivity;
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.attachments.Attachment;
@ -74,7 +73,6 @@ import org.thoughtcrime.securesms.conversation.ConversationAdapter.ItemClickList
import org.thoughtcrime.securesms.conversation.ConversationAdapter.StickyHeaderViewHolder;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MessagingDatabase;
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.RecipientDatabase;
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
import org.thoughtcrime.securesms.database.model.MessageRecord;
@ -87,6 +85,7 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.longmessage.LongMessageActivity;
import org.thoughtcrime.securesms.mediasend.Media;
import org.thoughtcrime.securesms.messagedetails.MessageDetailsActivity;
import org.thoughtcrime.securesms.messagerequests.MessageRequestViewModel;
import org.thoughtcrime.securesms.mms.GlideApp;
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage;
@ -690,13 +689,7 @@ public class ConversationFragment extends Fragment {
private void handleDisplayDetails(MessageRecord message) {
Intent intent = new Intent(getActivity(), org.thoughtcrime.securesms.messagedetails.MessageDetailsActivity.class);
intent.putExtra(MessageDetailsActivity.MESSAGE_ID_EXTRA, message.getId());
intent.putExtra(MessageDetailsActivity.THREAD_ID_EXTRA, threadId);
intent.putExtra(MessageDetailsActivity.TYPE_EXTRA, message.isMms() ? MmsSmsDatabase.MMS_TRANSPORT : MmsSmsDatabase.SMS_TRANSPORT);
intent.putExtra(MessageDetailsActivity.RECIPIENT_EXTRA, recipient.getId());
intent.putExtra(MessageDetailsActivity.IS_PUSH_GROUP_EXTRA, recipient.get().isGroup() && message.isPush());
startActivity(intent);
startActivity(MessageDetailsActivity.getIntentForMessageDetails(requireContext(), message, recipient.getId(), threadId));
}
private void handleForwardMessage(MessageRecord message) {

View File

@ -58,7 +58,6 @@ import com.annimon.stream.Stream;
import org.thoughtcrime.securesms.BindableConversationItem;
import org.thoughtcrime.securesms.ConfirmIdentityDialog;
import org.thoughtcrime.securesms.MediaPreviewActivity;
import org.thoughtcrime.securesms.MessageDetailsActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.attachments.DatabaseAttachment;
import org.thoughtcrime.securesms.components.AlertView;
@ -77,7 +76,6 @@ import org.thoughtcrime.securesms.contactshare.Contact;
import org.thoughtcrime.securesms.database.AttachmentDatabase;
import org.thoughtcrime.securesms.database.DatabaseFactory;
import org.thoughtcrime.securesms.database.MmsDatabase;
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.SmsDatabase;
import org.thoughtcrime.securesms.database.documents.IdentityKeyMismatch;
import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord;
@ -92,6 +90,7 @@ import org.thoughtcrime.securesms.jobs.SmsSendJob;
import org.thoughtcrime.securesms.linkpreview.LinkPreview;
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil;
import org.thoughtcrime.securesms.logging.Log;
import org.thoughtcrime.securesms.messagedetails.MessageDetailsActivity;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.mms.ImageSlide;
import org.thoughtcrime.securesms.mms.PartAuthority;
@ -109,7 +108,6 @@ import org.thoughtcrime.securesms.revealable.ViewOnceUtil;
import org.thoughtcrime.securesms.stickers.StickerUrl;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.DynamicTheme;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.thoughtcrime.securesms.util.LongClickCopySpan;
import org.thoughtcrime.securesms.util.LongClickMovementMethod;
import org.thoughtcrime.securesms.util.SearchUtil;
@ -1377,13 +1375,7 @@ public class ConversationItem extends LinearLayout implements BindableConversati
if (!shouldInterceptClicks(messageRecord) && parent != null) {
parent.onClick(v);
} else if (messageRecord.isFailed()) {
Intent intent = new Intent(context, org.thoughtcrime.securesms.messagedetails.MessageDetailsActivity.class);
intent.putExtra(MessageDetailsActivity.MESSAGE_ID_EXTRA, messageRecord.getId());
intent.putExtra(MessageDetailsActivity.THREAD_ID_EXTRA, messageRecord.getThreadId());
intent.putExtra(MessageDetailsActivity.TYPE_EXTRA, messageRecord.isMms() ? MmsSmsDatabase.MMS_TRANSPORT : MmsSmsDatabase.SMS_TRANSPORT);
intent.putExtra(MessageDetailsActivity.IS_PUSH_GROUP_EXTRA, groupThread && messageRecord.isPush());
intent.putExtra(MessageDetailsActivity.RECIPIENT_EXTRA, conversationRecipient.getId());
context.startActivity(intent);
context.startActivity(MessageDetailsActivity.getIntentForMessageDetails(context, messageRecord, conversationRecipient.getId(), messageRecord.getThreadId()));
} else if (!messageRecord.isOutgoing() && messageRecord.isIdentityMismatchFailure()) {
handleApproveIdentity();
} else if (messageRecord.isPendingInsecureSmsFallback()) {

View File

@ -1,16 +1,21 @@
package org.thoughtcrime.securesms.messagedetails;
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.os.Bundle;
import android.view.MenuItem;
import androidx.annotation.NonNull;
import androidx.lifecycle.ViewModelProviders;
import androidx.recyclerview.widget.RecyclerView;
import org.thoughtcrime.securesms.PassphraseRequiredActionBarActivity;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.color.MaterialColor;
import org.thoughtcrime.securesms.database.MmsSmsDatabase;
import org.thoughtcrime.securesms.database.model.MessageRecord;
import org.thoughtcrime.securesms.messagedetails.MessageDetailsAdapter.MessageDetailsViewState;
import org.thoughtcrime.securesms.messagedetails.MessageDetailsViewModel.Factory;
import org.thoughtcrime.securesms.mms.GlideApp;
@ -25,10 +30,10 @@ import java.util.List;
public final class MessageDetailsActivity extends PassphraseRequiredActionBarActivity {
public static final String MESSAGE_ID_EXTRA = "message_id";
public static final String THREAD_ID_EXTRA = "thread_id";
public static final String TYPE_EXTRA = "type";
public static final String RECIPIENT_EXTRA = "recipient_id";
private static final String MESSAGE_ID_EXTRA = "message_id";
private static final String THREAD_ID_EXTRA = "thread_id";
private static final String TYPE_EXTRA = "type";
private static final String RECIPIENT_EXTRA = "recipient_id";
private GlideRequests glideRequests;
private MessageDetailsViewModel viewModel;
@ -36,6 +41,15 @@ public final class MessageDetailsActivity extends PassphraseRequiredActionBarAct
private DynamicTheme dynamicTheme = new DynamicDarkActionBarTheme();
public static @NonNull Intent getIntentForMessageDetails(@NonNull Context context, @NonNull MessageRecord message, @NonNull RecipientId recipientId, long threadId) {
Intent intent = new Intent(context, MessageDetailsActivity.class);
intent.putExtra(MESSAGE_ID_EXTRA, message.getId());
intent.putExtra(THREAD_ID_EXTRA, threadId);
intent.putExtra(TYPE_EXTRA, message.isMms() ? MmsSmsDatabase.MMS_TRANSPORT : MmsSmsDatabase.SMS_TRANSPORT);
intent.putExtra(RECIPIENT_EXTRA, recipientId);
return intent;
}
@Override
protected void onPreCreate() {
dynamicTheme.onCreate(this);
@ -44,7 +58,7 @@ public final class MessageDetailsActivity extends PassphraseRequiredActionBarAct
@Override
protected void onCreate(Bundle savedInstanceState, boolean ready) {
super.onCreate(savedInstanceState, ready);
setContentView(R.layout.message_details_2_activity);
setContentView(R.layout.message_details_activity);
glideRequests = GlideApp.with(this);

View File

@ -32,11 +32,11 @@ final class MessageDetailsAdapter extends ListAdapter<MessageDetailsAdapter.Mess
public @NonNull RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
switch (viewType) {
case MessageDetailsViewState.MESSAGE_HEADER:
return new MessageHeaderViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.message_details_2_header, parent, false), glideRequests);
return new MessageHeaderViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.message_details_header, parent, false), glideRequests);
case MessageDetailsViewState.RECIPIENT_HEADER:
return new RecipientHeaderViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.message_details_2_recipient_header, parent, false));
return new RecipientHeaderViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.message_details_recipient_header, parent, false));
case MessageDetailsViewState.RECIPIENT:
return new RecipientViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.message_details_2_recipient, parent, false));
return new RecipientViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.message_details_recipient, parent, false));
default:
throw new AssertionError("unknown view type");
}

View File

@ -48,18 +48,18 @@ final class MessageHeaderViewHolder extends RecyclerView.ViewHolder {
super(itemView);
this.glideRequests = glideRequests;
sentDate = itemView.findViewById(R.id.sent_time);
receivedDate = itemView.findViewById(R.id.received_time);
receivedGroup = itemView.findViewById(R.id.received_group);
expiresIn = itemView.findViewById(R.id.expires_in);
expiresGroup = itemView.findViewById(R.id.expires_group);
transport = itemView.findViewById(R.id.transport);
errorText = itemView.findViewById(R.id.error_text);
resendButton = itemView.findViewById(R.id.resend_button);
messageMetadata = itemView.findViewById(R.id.message_metadata);
updateStub = itemView.findViewById(R.id.message_view_update);
sentStub = itemView.findViewById(R.id.message_view_sent_multimedia);
receivedStub = itemView.findViewById(R.id.message_view_received_multimedia);
sentDate = itemView.findViewById(R.id.message_details_header_sent_time);
receivedDate = itemView.findViewById(R.id.message_details_header_received_time);
receivedGroup = itemView.findViewById(R.id.message_details_header_received_group);
expiresIn = itemView.findViewById(R.id.message_details_header_expires_in);
expiresGroup = itemView.findViewById(R.id.message_details_header_expires_group);
transport = itemView.findViewById(R.id.message_details_header_transport);
errorText = itemView.findViewById(R.id.message_details_header_error_text);
resendButton = itemView.findViewById(R.id.message_details_header_resend_button);
messageMetadata = itemView.findViewById(R.id.message_details_header_message_metadata);
updateStub = itemView.findViewById(R.id.message_details_header_message_view_update);
sentStub = itemView.findViewById(R.id.message_details_header_message_view_sent_multimedia);
receivedStub = itemView.findViewById(R.id.message_details_header_message_view_received_multimedia);
}
void bind(MessageRecord messageRecord, boolean running) {

View File

@ -9,12 +9,9 @@ import org.thoughtcrime.securesms.ConfirmIdentityDialog;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.AvatarImageView;
import org.thoughtcrime.securesms.components.FromTextView;
import org.thoughtcrime.securesms.mms.GlideRequests;
import org.thoughtcrime.securesms.util.DateUtils;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.Locale;
final class RecipientViewHolder extends RecyclerView.ViewHolder {
@ -28,12 +25,12 @@ final class RecipientViewHolder extends RecyclerView.ViewHolder {
RecipientViewHolder(View itemView) {
super(itemView);
fromView = itemView.findViewById(R.id.recipient_name);
avatar = itemView.findViewById(R.id.recipient_avatar);
timestamp = itemView.findViewById(R.id.recipient_timestamp);
error = itemView.findViewById(R.id.error_description);
conflictButton = itemView.findViewById(R.id.conflict_button);
unidentifiedDeliveryIcon = itemView.findViewById(R.id.ud_indicator);
fromView = itemView.findViewById(R.id.message_details_recipient_name);
avatar = itemView.findViewById(R.id.message_details_recipient_avatar);
timestamp = itemView.findViewById(R.id.message_details_recipient_timestamp);
error = itemView.findViewById(R.id.message_details_recipient_error_description);
conflictButton = itemView.findViewById(R.id.message_details_recipient_conflict_button);
unidentifiedDeliveryIcon = itemView.findViewById(R.id.message_details_recipient_ud_indicator);
}
void bind(RecipientDeliveryStatus data) {
@ -45,13 +42,13 @@ final class RecipientViewHolder extends RecyclerView.ViewHolder {
timestamp.setVisibility(View.GONE);
error.setVisibility(View.VISIBLE);
conflictButton.setVisibility(View.VISIBLE);
error.setText(itemView.getContext().getString(R.string.MessageDetailsRecipient_new_safety_number));
error.setText(itemView.getContext().getString(R.string.message_details_recipient__new_safety_number));
conflictButton.setOnClickListener(unused -> new ConfirmIdentityDialog(itemView.getContext(), data.getMessageRecord(), data.getKeyMismatchFailure()).show());
} else if ((data.getNetworkFailure() != null && !data.getMessageRecord().isPending()) || (!data.getMessageRecord().getRecipient().isPushGroup() && data.getMessageRecord().isFailed())) {
timestamp.setVisibility(View.GONE);
error.setVisibility(View.VISIBLE);
conflictButton.setVisibility(View.GONE);
error.setText(itemView.getContext().getString(R.string.MessageDetailsRecipient_failed_to_send));
error.setText(itemView.getContext().getString(R.string.message_details_recipient__failed_to_send));
} else {
timestamp.setVisibility(View.VISIBLE);
error.setVisibility(View.GONE);

View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/message_details_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?pref_divider"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

View File

@ -1,189 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/group_media_card"
style="@style/Widget.Signal.CardView.PreferenceRow"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="16dp"
android:paddingTop="24dp"
android:paddingEnd="16dp"
android:paddingBottom="24dp">
<FrameLayout
android:id="@+id/message_view"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ViewStub
android:id="@+id/message_view_update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/conversation_item_update"/>
<ViewStub
android:id="@+id/message_view_sent_multimedia"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/conversation_item_sent_multimedia"/>
<ViewStub
android:id="@+id/message_view_received_multimedia"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/conversation_item_received_multimedia"/>
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/error_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:visibility="gone"
android:textSize="16sp"
android:padding="5dp"
tools:visibility="visible"
android:text="@string/message_details_header__issues_need_your_attention"
android:drawablePadding="4dp"
app:drawableStartCompat="@drawable/ic_info_outline_message_details_24"
android:gravity="center_vertical" />
<Button
android:id="@+id/resend_button"
android:layout_width="wrap_content"
android:layout_height="38sp"
style="@style/InfoButton"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:layout_gravity="center_vertical"
android:drawableStart="@drawable/ic_refresh_white_18dp"
android:text="@string/message_recipients_list_item__resend"
android:visibility="gone"
tools:visibility="visible" />
</LinearLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/message_metadata"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/sent_time_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="end"
android:text="@string/message_details_header__sent"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/sent_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_details_table_row_pad"
android:background="?selectableItemBackground"
app:layout_constraintBottom_toBottomOf="@+id/sent_time_label"
app:layout_constraintStart_toEndOf="@+id/label_barrier"
tools:text="Jan 18, 2015, 12:29:37 AM GMT-08:00" />
<TextView
android:id="@+id/received_time_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="end"
android:text="@string/message_details_header__received"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/sent_time_label" />
<TextView
android:id="@+id/received_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_details_table_row_pad"
android:background="?selectableItemBackground"
app:layout_constraintBottom_toBottomOf="@+id/received_time_label"
app:layout_constraintStart_toEndOf="@id/label_barrier"
tools:text="Jan 18, 2015, 12:31:15 AM GMT-08:00" />
<androidx.constraintlayout.widget.Group
android:id="@+id/received_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="received_time_label,received_time" />
<TextView
android:id="@+id/expires_in_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="end"
android:text="@string/message_details_header__disappears"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/received_time_label" />
<TextView
android:id="@+id/expires_in"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_details_table_row_pad"
app:layout_constraintBottom_toBottomOf="@+id/expires_in_label"
app:layout_constraintStart_toEndOf="@id/label_barrier"
tools:text="1 week" />
<androidx.constraintlayout.widget.Group
android:id="@+id/expires_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="expires_in_label,expires_in" />
<TextView
android:id="@+id/transport_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="end"
android:text="@string/message_details_header__via"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/expires_in_label" />
<TextView
android:id="@+id/transport"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_details_table_row_pad"
app:layout_constraintBottom_toBottomOf="@+id/transport_label"
app:layout_constraintStart_toEndOf="@id/label_barrier"
tools:text="Push (TextSecure)" />
<androidx.constraintlayout.widget.Barrier
android:id="@+id/label_barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="sent_time_label,received_time_label,expires_in_label" />
</androidx.constraintlayout.widget.ConstraintLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>

View File

@ -1,14 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/container"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView android:id="@+id/recipients_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:listitem="@layout/message_recipient_list_item" />
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/message_details_list"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="?pref_divider"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" />

View File

@ -1,32 +1,51 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout android:id="@+id/item_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="15dp"
android:paddingBottom="15dp"
android:elevation="2dp" />
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/group_media_card"
style="@style/Widget.Signal.CardView.PreferenceRow"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:paddingStart="10dp"
android:paddingEnd="10dp">
android:paddingStart="16dp"
android:paddingTop="24dp"
android:paddingEnd="16dp"
android:paddingBottom="24dp">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<ViewStub
android:id="@+id/message_details_header_message_view_update"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/conversation_item_update"/>
<ViewStub
android:id="@+id/message_details_header_message_view_sent_multimedia"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/conversation_item_sent_multimedia"/>
<ViewStub
android:id="@+id/message_details_header_message_view_received_multimedia"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout="@layout/conversation_item_received_multimedia"/>
</FrameLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.appcompat.widget.AppCompatTextView
android:id="@+id/error_text"
android:id="@+id/message_details_header_error_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
@ -40,7 +59,7 @@
android:gravity="center_vertical" />
<Button
android:id="@+id/resend_button"
android:id="@+id/message_details_header_resend_button"
android:layout_width="wrap_content"
android:layout_height="38sp"
style="@style/InfoButton"
@ -56,100 +75,114 @@
</LinearLayout>
<TableLayout android:id="@+id/metadata_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:shrinkColumns="1">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="@+id/message_details_header_message_metadata"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TableRow android:id="@+id/sent_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/message_details_table_row_pad">
<TextView
android:id="@+id/message_details_header_sent_time_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="end"
android:text="@string/message_details_header__sent"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/message_details_header__sent"
android:gravity="end"
android:textStyle="bold" />
<TextView
android:id="@+id/message_details_header_sent_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_details_table_row_pad"
android:background="?selectableItemBackground"
app:layout_constraintBottom_toBottomOf="@+id/message_details_header_sent_time_label"
app:layout_constraintStart_toEndOf="@+id/message_details_header_label_barrier"
tools:text="Jan 18, 2015, 12:29:37 AM GMT-08:00" />
<TextView android:id="@+id/sent_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_details_table_row_pad"
tools:text="Jan 18, 2015, 12:29:37 AM GMT-08:00" />
<TextView
android:id="@+id/message_details_header_received_time_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="end"
android:text="@string/message_details_header__received"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/message_details_header_sent_time_label" />
</TableRow>
<TextView
android:id="@+id/message_details_header_received_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_details_table_row_pad"
android:background="?selectableItemBackground"
app:layout_constraintBottom_toBottomOf="@+id/message_details_header_received_time_label"
app:layout_constraintStart_toEndOf="@id/message_details_header_label_barrier"
tools:text="Jan 18, 2015, 12:31:15 AM GMT-08:00" />
<TableRow android:id="@+id/received_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/message_details_table_row_pad">
<androidx.constraintlayout.widget.Group
android:id="@+id/message_details_header_received_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="message_details_header_received_time_label,message_details_header_received_time" />
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/message_details_header__received"
android:gravity="end"
android:textStyle="bold" />
<TextView
android:id="@+id/message_details_header_expires_in_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="end"
android:text="@string/message_details_header__disappears"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/message_details_header_received_time_label" />
<TextView android:id="@+id/received_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_details_table_row_pad"
tools:text="Jan 18, 2015, 12:31:15 AM GMT-08:00" />
<TextView
android:id="@+id/message_details_header_expires_in"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_details_table_row_pad"
app:layout_constraintBottom_toBottomOf="@+id/message_details_header_expires_in_label"
app:layout_constraintStart_toEndOf="@id/message_details_header_label_barrier"
tools:text="1 week" />
</TableRow>
<androidx.constraintlayout.widget.Group
android:id="@+id/message_details_header_expires_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="message_details_header_expires_in_label,message_details_header_expires_in" />
<TableRow android:id="@+id/expires_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="@dimen/message_details_table_row_pad"
android:visibility="gone"
tools:visibility="visible">
<TextView
android:id="@+id/message_details_header_transport_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:gravity="end"
android:text="@string/message_details_header__via"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/message_details_header_expires_in_label" />
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/message_details_header__disappears"
android:gravity="end"
android:textStyle="bold"/>
<TextView
android:id="@+id/message_details_header_transport"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_details_table_row_pad"
app:layout_constraintBottom_toBottomOf="@+id/message_details_header_transport_label"
app:layout_constraintStart_toEndOf="@id/message_details_header_label_barrier"
tools:text="Push (TextSecure)" />
<TextView android:id="@+id/expires_in"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_details_table_row_pad"
tools:text="1 week"/>
<androidx.constraintlayout.widget.Barrier
android:id="@+id/message_details_header_label_barrier"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="message_details_header_sent_time_label,message_details_header_received_time_label,message_details_header_expires_in_label" />
</TableRow>
</androidx.constraintlayout.widget.ConstraintLayout>
<TableRow android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/message_details_table_row_pad">
<TextView android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/message_details_header__via"
android:gravity="end"
android:textStyle="bold" />
<TextView android:id="@+id/transport"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/message_details_table_row_pad"
tools:text="Push (TextSecure)" />
</TableRow>
<TableRow android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="@dimen/message_details_table_row_pad">
<TextView android:id="@+id/tofrom"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="@string/message_details_header__to"
android:textStyle="bold" />
</TableRow>
</TableLayout>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>

View File

@ -14,7 +14,7 @@
android:padding="16dp">
<org.thoughtcrime.securesms.components.AvatarImageView
android:id="@+id/recipient_avatar"
android:id="@+id/message_details_recipient_avatar"
android:foreground="@drawable/contact_photo_background"
android:layout_width="36dp"
android:layout_height="36dp"
@ -23,12 +23,12 @@
tools:src="@drawable/ic_contact_picture"
android:contentDescription="@string/SingleContactSelectionActivity_contact_photo"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@+id/recipient_name"
app:layout_constraintEnd_toStartOf="@+id/message_details_recipient_name"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<org.thoughtcrime.securesms.components.FromTextView
android:id="@+id/recipient_name"
android:id="@+id/message_details_recipient_name"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="4dp"
@ -37,34 +37,34 @@
android:singleLine="true"
tools:text="Jules Bonnot"
android:ellipsize="marquee"
app:layout_constraintStart_toEndOf="@+id/recipient_avatar"
app:layout_constraintEnd_toStartOf="@+id/recipient_timestamp"
app:layout_constraintStart_toEndOf="@+id/message_details_recipient_avatar"
app:layout_constraintEnd_toStartOf="@+id/message_details_recipient_timestamp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="@+id/error_description"/>
app:layout_constraintBottom_toTopOf="@+id/message_details_recipient_error_description"/>
<TextView android:id="@+id/error_description"
<TextView android:id="@+id/message_details_recipient_error_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFF44336"
android:visibility="gone"
tools:visibility="visible"
tools:text="New identity"
app:layout_constraintStart_toStartOf="@+id/recipient_name"
app:layout_constraintTop_toBottomOf="@+id/recipient_name"
app:layout_constraintStart_toStartOf="@+id/message_details_recipient_name"
app:layout_constraintTop_toBottomOf="@+id/message_details_recipient_name"
app:layout_constraintBottom_toBottomOf="parent"/>
<TextView
android:id="@+id/recipient_timestamp"
android:id="@+id/message_details_recipient_timestamp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
tools:text="05/27/20 1:32 PM"
app:layout_constraintStart_toEndOf="@+id/recipient_name"
app:layout_constraintEnd_toStartOf="@+id/conflict_button"
app:layout_constraintStart_toEndOf="@+id/message_details_recipient_name"
app:layout_constraintEnd_toStartOf="@+id/message_details_recipient_conflict_button"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<Button
android:id="@+id/conflict_button"
android:id="@+id/message_details_recipient_conflict_button"
android:layout_width="wrap_content"
android:layout_height="36dp"
style="@style/ErrorButton"
@ -75,20 +75,20 @@
android:drawableStart="@drawable/ic_error_white_18dp"
android:text="@string/message_recipients_list_item__view"
android:visibility="gone"
app:layout_constraintStart_toEndOf="@+id/recipient_timestamp"
app:layout_constraintEnd_toStartOf="@+id/ud_indicator"
app:layout_constraintStart_toEndOf="@+id/message_details_recipient_timestamp"
app:layout_constraintEnd_toStartOf="@+id/message_details_recipient_ud_indicator"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
tools:visibility="gone" />
<ImageView android:id="@+id/ud_indicator"
<ImageView android:id="@+id/message_details_recipient_ud_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginEnd="4dp"
android:src="@drawable/ic_unidentified_delivery"
android:tint="?attr/conversation_item_sent_text_secondary_color"
app:layout_constraintStart_toEndOf="@+id/conflict_button"
app:layout_constraintStart_toEndOf="@+id/message_details_recipient_conflict_button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>

View File

@ -1,99 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<org.thoughtcrime.securesms.MessageRecipientListItem
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp">
<org.thoughtcrime.securesms.components.AvatarImageView
android:id="@+id/contact_photo_image"
android:foreground="@drawable/contact_photo_background"
android:layout_width="40dp"
android:layout_height="40dp"
android:layout_centerVertical="true"
android:layout_alignParentStart="true"
android:layout_marginTop="3dp"
android:layout_marginBottom="3dp"
android:layout_marginEnd="10dp"
android:cropToPadding="true"
tools:src="@drawable/ic_contact_picture"
android:contentDescription="@string/SingleContactSelectionActivity_contact_photo" />
<LinearLayout android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="4dip"
android:layout_marginBottom="4dip"
android:layout_toEndOf="@id/contact_photo_image"
android:layout_centerVertical="true"
android:gravity="center_vertical"
android:orientation="horizontal">
<LinearLayout android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content"
android:orientation="vertical">
<org.thoughtcrime.securesms.components.FromTextView
android:id="@+id/from"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textColor="?attr/conversation_list_item_contact_color"
android:singleLine="true"
android:gravity="center_vertical"
android:layout_gravity="center_vertical"
tools:text="Jules Bonnot"
android:ellipsize="marquee" />
<TextView android:id="@+id/error_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#FFF44336"
android:visibility="gone"
tools:visibility="visible"
tools:text="New identity" />
<TextView android:id="@+id/action_description"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="gone"
tools:visibility="visible"
tools:text="action" />
</LinearLayout>
<Button android:id="@+id/conflict_button"
android:layout_width="wrap_content"
android:layout_height="38sp"
style="@style/ErrorButton"
android:paddingStart="10dp"
android:paddingEnd="10dp"
android:paddingTop="5dp"
android:paddingBottom="5dp"
android:layout_gravity="center_vertical"
android:drawableStart="@drawable/ic_error_white_18dp"
android:text="@string/message_recipients_list_item__view"
android:visibility="gone"
tools:visibility="gone" />
<ImageView android:id="@+id/ud_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="4dp"
android:layout_marginEnd="4dp"
android:src="@drawable/ic_unidentified_delivery"
android:tint="?attr/conversation_item_sent_text_secondary_color"/>
<org.thoughtcrime.securesms.components.DeliveryStatusView
android:id="@+id/delivery_status"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:iconColor="?attr/conversation_item_sent_text_secondary_color"
android:visibility="gone"/>
</LinearLayout>
</org.thoughtcrime.securesms.MessageRecipientListItem>

View File

@ -647,10 +647,6 @@
<!-- LearnMoreTextView -->
<string name="LearnMoreTextView_learn_more">Learn more</string>
<!-- MessageDetailsRecipient -->
<string name="MessageDetailsRecipient_failed_to_send">Failed to send</string>
<string name="MessageDetailsRecipient_new_safety_number">New safety number</string>
<!-- LongMessageActivity -->
<string name="LongMessageActivity_unable_to_find_message">Unable to find message</string>
<string name="LongMessageActivity_message_from_s">Message from %1$s</string>
@ -1713,9 +1709,6 @@
<string name="message_details_header__received">Received</string>
<string name="message_details_header__disappears">Disappears</string>
<string name="message_details_header__via">Via</string>
<string name="message_details_header__to">To:</string>
<string name="message_details_header__from">From:</string>
<string name="message_details_header__with">With:</string>
<!-- message_details_recipient_header -->
<string name="message_details_recipient_header__pending_send">Pending</string>
@ -1725,6 +1718,10 @@
<string name="message_details_recipient_header__read_by">Read by</string>
<string name="message_details_recipient_header__not_sent">Not sent</string>
<!-- message_Details_recipient -->
<string name="message_details_recipient__failed_to_send">Failed to send</string>
<string name="message_details_recipient__new_safety_number">New safety number</string>
<!-- AndroidManifest.xml -->
<string name="AndroidManifest__create_passphrase">Create passphrase</string>
<string name="AndroidManifest__select_contacts">Select contacts</string>