Merge pull request #6303 from thundernest/message-header-rewritten
Message View Redesign - Part 1: Change header
This commit is contained in:
commit
923b804aed
7 changed files with 265 additions and 537 deletions
|
@ -0,0 +1,21 @@
|
|||
package com.fsck.k9.ui.helper
|
||||
|
||||
import android.content.Context
|
||||
import android.util.AttributeSet
|
||||
import androidx.appcompat.widget.AppCompatTextView
|
||||
|
||||
/**
|
||||
* Return the baseline of the last line of text, instead of TextView's default of the first line.
|
||||
*/
|
||||
// Source: https://stackoverflow.com/a/62419876
|
||||
class BottomBaselineTextView @JvmOverloads constructor(
|
||||
context: Context,
|
||||
attrs: AttributeSet? = null
|
||||
) : AppCompatTextView(context, attrs) {
|
||||
|
||||
override fun getBaseline(): Int {
|
||||
val layout = layout ?: return super.getBaseline()
|
||||
val baselineOffset = super.getBaseline() - layout.getLineBaseline(0)
|
||||
return baselineOffset + layout.getLineBaseline(layout.lineCount - 1)
|
||||
}
|
||||
}
|
|
@ -238,7 +238,6 @@ public class MessageTopView extends LinearLayout {
|
|||
|
||||
public void setMessageCryptoPresenter(MessageCryptoPresenter messageCryptoPresenter) {
|
||||
this.messageCryptoPresenter = messageCryptoPresenter;
|
||||
mHeaderContainer.setOnCryptoClickListener(messageCryptoPresenter);
|
||||
}
|
||||
|
||||
public void enableDownloadButton() {
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
package com.fsck.k9.view;
|
||||
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.text.format.DateUtils;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.View.OnLongClickListener;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
@ -21,119 +17,64 @@ import androidx.appcompat.widget.PopupMenu;
|
|||
import androidx.appcompat.widget.PopupMenu.OnMenuItemClickListener;
|
||||
import com.fsck.k9.Account;
|
||||
import com.fsck.k9.DI;
|
||||
import com.fsck.k9.FontSizes;
|
||||
import com.fsck.k9.K9;
|
||||
import com.fsck.k9.activity.misc.ContactPicture;
|
||||
import com.fsck.k9.contacts.ContactPictureLoader;
|
||||
import com.fsck.k9.helper.ClipboardManager;
|
||||
import com.fsck.k9.helper.Contacts;
|
||||
import com.fsck.k9.helper.MessageHelper;
|
||||
import com.fsck.k9.mail.Address;
|
||||
import com.fsck.k9.mail.Flag;
|
||||
import com.fsck.k9.mail.Message;
|
||||
import com.fsck.k9.ui.ContactBadge;
|
||||
import com.fsck.k9.ui.R;
|
||||
import com.fsck.k9.ui.messageview.OnCryptoClickListener;
|
||||
import timber.log.Timber;
|
||||
import com.google.android.material.chip.Chip;
|
||||
import com.google.android.material.snackbar.Snackbar;
|
||||
|
||||
|
||||
public class MessageHeader extends LinearLayout implements OnClickListener, OnLongClickListener {
|
||||
private static final int DEFAULT_SUBJECT_LINES = 3;
|
||||
|
||||
private final ClipboardManager clipboardManager = DI.get(ClipboardManager.class);
|
||||
private Chip accountChip;
|
||||
private TextView subjectView;
|
||||
private ImageView starView;
|
||||
private ImageView contactPictureView;
|
||||
private TextView fromView;
|
||||
private ImageView cryptoStatusIcon;
|
||||
|
||||
private Context mContext;
|
||||
private TextView mFromView;
|
||||
private TextView mSenderView;
|
||||
private TextView mDateView;
|
||||
private TextView mToView;
|
||||
private TextView mToLabel;
|
||||
private TextView mCcView;
|
||||
private TextView mCcLabel;
|
||||
private TextView mBccView;
|
||||
private TextView mBccLabel;
|
||||
private TextView mSubjectView;
|
||||
private ImageView mCryptoStatusIcon;
|
||||
private MessageHelper messageHelper;
|
||||
|
||||
private View mChip;
|
||||
private CheckBox mFlagged;
|
||||
private int defaultSubjectColor;
|
||||
private View singleMessageOptionIcon;
|
||||
private View mAnsweredIcon;
|
||||
private View mForwardedIcon;
|
||||
private Message mMessage;
|
||||
private Account mAccount;
|
||||
private FontSizes mFontSizes = K9.getFontSizes();
|
||||
private Contacts mContacts;
|
||||
|
||||
private MessageHelper mMessageHelper;
|
||||
private ContactPictureLoader mContactsPictureLoader;
|
||||
private ContactBadge mContactBadge;
|
||||
|
||||
private OnCryptoClickListener onCryptoClickListener;
|
||||
private OnMenuItemClickListener onMenuItemClickListener;
|
||||
|
||||
|
||||
public MessageHeader(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mContext = context;
|
||||
mContacts = Contacts.getInstance(mContext);
|
||||
|
||||
if (!isInEditMode()) {
|
||||
messageHelper = MessageHelper.getInstance(getContext());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
mAnsweredIcon = findViewById(R.id.answered);
|
||||
mForwardedIcon = findViewById(R.id.forwarded);
|
||||
mFromView = findViewById(R.id.from);
|
||||
mSenderView = findViewById(R.id.sender);
|
||||
mToView = findViewById(R.id.to);
|
||||
mToLabel = findViewById(R.id.to_label);
|
||||
mCcView = findViewById(R.id.cc);
|
||||
mCcLabel = findViewById(R.id.cc_label);
|
||||
mBccView = findViewById(R.id.bcc);
|
||||
mBccLabel = findViewById(R.id.bcc_label);
|
||||
accountChip = findViewById(R.id.chip);
|
||||
subjectView = findViewById(R.id.subject);
|
||||
starView = findViewById(R.id.flagged);
|
||||
contactPictureView = findViewById(R.id.contact_picture);
|
||||
fromView = findViewById(R.id.from);
|
||||
cryptoStatusIcon = findViewById(R.id.crypto_status_icon);
|
||||
|
||||
mContactBadge = findViewById(R.id.contact_badge);
|
||||
subjectView.setOnClickListener(this);
|
||||
subjectView.setOnLongClickListener(this);
|
||||
|
||||
singleMessageOptionIcon = findViewById(R.id.icon_single_message_options);
|
||||
View menuPrimaryActionView = findViewById(R.id.menu_primary_action);
|
||||
menuPrimaryActionView.setOnClickListener(this);
|
||||
menuPrimaryActionView.setOnLongClickListener(this);
|
||||
|
||||
mSubjectView = findViewById(R.id.subject);
|
||||
mChip = findViewById(R.id.chip);
|
||||
mDateView = findViewById(R.id.date);
|
||||
mFlagged = findViewById(R.id.flagged);
|
||||
View menuOverflowView = findViewById(R.id.menu_overflow);
|
||||
menuOverflowView.setOnClickListener(this);
|
||||
menuOverflowView.setOnLongClickListener(this);
|
||||
|
||||
defaultSubjectColor = mSubjectView.getCurrentTextColor();
|
||||
mFontSizes.setViewTextSize(mSubjectView, mFontSizes.getMessageViewSubject());
|
||||
mFontSizes.setViewTextSize(mDateView, mFontSizes.getMessageViewDate());
|
||||
|
||||
mFontSizes.setViewTextSize(mFromView, mFontSizes.getMessageViewSender());
|
||||
mFontSizes.setViewTextSize(mToView, mFontSizes.getMessageViewTo());
|
||||
mFontSizes.setViewTextSize(mToLabel, mFontSizes.getMessageViewTo());
|
||||
mFontSizes.setViewTextSize(mCcView, mFontSizes.getMessageViewCC());
|
||||
mFontSizes.setViewTextSize(mCcLabel, mFontSizes.getMessageViewCC());
|
||||
mFontSizes.setViewTextSize(mBccView, mFontSizes.getMessageViewBCC());
|
||||
mFontSizes.setViewTextSize(mBccLabel, mFontSizes.getMessageViewBCC());
|
||||
|
||||
singleMessageOptionIcon.setOnClickListener(this);
|
||||
|
||||
mSubjectView.setOnClickListener(this);
|
||||
mFromView.setOnClickListener(this);
|
||||
mToView.setOnClickListener(this);
|
||||
mCcView.setOnClickListener(this);
|
||||
mBccView.setOnClickListener(this);
|
||||
|
||||
mSubjectView.setOnLongClickListener(this);
|
||||
mFromView.setOnLongClickListener(this);
|
||||
mToView.setOnLongClickListener(this);
|
||||
mCcView.setOnLongClickListener(this);
|
||||
mBccView.setOnLongClickListener(this);
|
||||
|
||||
mCryptoStatusIcon = findViewById(R.id.crypto_status_icon);
|
||||
mCryptoStatusIcon.setOnClickListener(this);
|
||||
|
||||
mMessageHelper = MessageHelper.getInstance(mContext);
|
||||
findViewById(R.id.participants_container).setOnClickListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -141,17 +82,15 @@ public class MessageHeader extends LinearLayout implements OnClickListener, OnLo
|
|||
int id = view.getId();
|
||||
if (id == R.id.subject) {
|
||||
toggleSubjectViewMaxLines();
|
||||
} else if (id == R.id.from) {
|
||||
onAddSenderToContacts();
|
||||
} else if (id == R.id.to || id == R.id.cc || id == R.id.bcc) {
|
||||
expand((TextView)view, ((TextView)view).getEllipsize() != null);
|
||||
} else if (id == R.id.crypto_status_icon) {
|
||||
onCryptoClickListener.onCryptoClick();
|
||||
} else if (id == R.id.icon_single_message_options) {
|
||||
} else if (id == R.id.menu_primary_action) {
|
||||
Snackbar.make(getRootView(), "TODO: Perform primary action", Snackbar.LENGTH_LONG).show();
|
||||
} else if (id == R.id.menu_overflow) {
|
||||
PopupMenu popupMenu = new PopupMenu(getContext(), view);
|
||||
popupMenu.setOnMenuItemClickListener(onMenuItemClickListener);
|
||||
popupMenu.inflate(R.menu.single_message_options);
|
||||
popupMenu.show();
|
||||
} else if (id == R.id.participants_container) {
|
||||
Snackbar.make(getRootView(), "TODO: Display details popup", Snackbar.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -160,149 +99,71 @@ public class MessageHeader extends LinearLayout implements OnClickListener, OnLo
|
|||
int id = view.getId();
|
||||
|
||||
if (id == R.id.subject) {
|
||||
onAddSubjectToClipboard(mSubjectView.getText().toString());
|
||||
} else if (id == R.id.from) {
|
||||
onAddAddressesToClipboard(mMessage.getFrom());
|
||||
} else if (id == R.id.to) {
|
||||
onAddRecipientsToClipboard(Message.RecipientType.TO);
|
||||
} else if (id == R.id.cc) {
|
||||
onAddRecipientsToClipboard(Message.RecipientType.CC);
|
||||
onAddSubjectToClipboard(subjectView.getText().toString());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void toggleSubjectViewMaxLines() {
|
||||
if (mSubjectView.getMaxLines() == DEFAULT_SUBJECT_LINES) {
|
||||
mSubjectView.setMaxLines(Integer.MAX_VALUE);
|
||||
if (subjectView.getMaxLines() == DEFAULT_SUBJECT_LINES) {
|
||||
subjectView.setMaxLines(Integer.MAX_VALUE);
|
||||
} else {
|
||||
mSubjectView.setMaxLines(DEFAULT_SUBJECT_LINES);
|
||||
subjectView.setMaxLines(DEFAULT_SUBJECT_LINES);
|
||||
}
|
||||
}
|
||||
|
||||
private void onAddSubjectToClipboard(String subject) {
|
||||
ClipboardManager clipboardManager = DI.get(ClipboardManager.class);
|
||||
clipboardManager.setText("subject", subject);
|
||||
|
||||
Toast.makeText(mContext, createMessageForSubject(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
private void onAddSenderToContacts() {
|
||||
if (mMessage != null) {
|
||||
try {
|
||||
final Address senderEmail = mMessage.getFrom()[0];
|
||||
mContacts.createContact(senderEmail);
|
||||
} catch (Exception e) {
|
||||
Timber.e(e, "Couldn't create contact");
|
||||
}
|
||||
}
|
||||
Toast.makeText(getContext(), createMessageForSubject(), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
public String createMessageForSubject() {
|
||||
return mContext.getResources().getString(R.string.copy_subject_to_clipboard);
|
||||
}
|
||||
|
||||
public String createMessage(int addressesCount) {
|
||||
return mContext.getResources().getQuantityString(R.plurals.copy_address_to_clipboard, addressesCount);
|
||||
}
|
||||
|
||||
private void onAddAddressesToClipboard(Address[] addresses) {
|
||||
String addressList = Address.toString(addresses);
|
||||
clipboardManager.setText("addresses", addressList);
|
||||
|
||||
Toast.makeText(mContext, createMessage(addresses.length), Toast.LENGTH_LONG).show();
|
||||
}
|
||||
|
||||
private void onAddRecipientsToClipboard(Message.RecipientType recipientType) {
|
||||
onAddAddressesToClipboard(mMessage.getRecipients(recipientType));
|
||||
return getResources().getString(R.string.copy_subject_to_clipboard);
|
||||
}
|
||||
|
||||
public void setOnFlagListener(OnClickListener listener) {
|
||||
mFlagged.setOnClickListener(listener);
|
||||
starView.setOnClickListener(listener);
|
||||
}
|
||||
|
||||
public void populate(final Message message, final Account account, boolean showStar) {
|
||||
accountChip.setText(account.getDisplayName());
|
||||
accountChip.setChipBackgroundColor(ColorStateList.valueOf(account.getChipColor()));
|
||||
|
||||
Address fromAddress = null;
|
||||
Address[] fromAddresses = message.getFrom();
|
||||
if (fromAddresses.length > 0) {
|
||||
fromAddress = fromAddresses[0];
|
||||
}
|
||||
|
||||
final Contacts contacts = K9.isShowContactName() ? mContacts : null;
|
||||
final CharSequence from = mMessageHelper.getSenderDisplayName(fromAddress);
|
||||
final CharSequence to = MessageHelper.toFriendly(message.getRecipients(Message.RecipientType.TO), contacts);
|
||||
final CharSequence cc = MessageHelper.toFriendly(message.getRecipients(Message.RecipientType.CC), contacts);
|
||||
final CharSequence bcc = MessageHelper.toFriendly(message.getRecipients(Message.RecipientType.BCC), contacts);
|
||||
|
||||
mMessage = message;
|
||||
mAccount = account;
|
||||
|
||||
if (K9.isShowContactPicture()) {
|
||||
mContactBadge.setVisibility(View.VISIBLE);
|
||||
mContactsPictureLoader = ContactPicture.getContactPictureLoader();
|
||||
} else {
|
||||
mContactBadge.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
if (shouldShowSender(message)) {
|
||||
mSenderView.setVisibility(VISIBLE);
|
||||
String sender = getResources().getString(R.string.message_view_sender_label,
|
||||
MessageHelper.toFriendly(message.getSender(), contacts));
|
||||
mSenderView.setText(sender);
|
||||
if (fromAddress != null) {
|
||||
ContactPictureLoader contactsPictureLoader = ContactPicture.getContactPictureLoader();
|
||||
contactsPictureLoader.setContactPicture(contactPictureView, fromAddress);
|
||||
} else {
|
||||
mSenderView.setVisibility(View.GONE);
|
||||
contactPictureView.setImageResource(R.drawable.ic_contact_picture);
|
||||
}
|
||||
|
||||
String dateTime = DateUtils.formatDateTime(mContext,
|
||||
message.getSentDate().getTime(),
|
||||
DateUtils.FORMAT_SHOW_DATE
|
||||
| DateUtils.FORMAT_ABBREV_ALL
|
||||
| DateUtils.FORMAT_SHOW_TIME
|
||||
| DateUtils.FORMAT_SHOW_YEAR);
|
||||
mDateView.setText(dateTime);
|
||||
|
||||
if (K9.isShowContactPicture()) {
|
||||
if (fromAddress != null) {
|
||||
mContactBadge.setContact(fromAddress);
|
||||
mContactsPictureLoader.setContactPicture(mContactBadge, fromAddress);
|
||||
} else {
|
||||
mContactBadge.setImageResource(R.drawable.ic_contact_picture);
|
||||
}
|
||||
}
|
||||
|
||||
mFromView.setText(from);
|
||||
|
||||
updateAddressField(mToView, to, mToLabel);
|
||||
updateAddressField(mCcView, cc, mCcLabel);
|
||||
updateAddressField(mBccView, bcc, mBccLabel);
|
||||
mAnsweredIcon.setVisibility(message.isSet(Flag.ANSWERED) ? View.VISIBLE : View.GONE);
|
||||
mForwardedIcon.setVisibility(message.isSet(Flag.FORWARDED) ? View.VISIBLE : View.GONE);
|
||||
CharSequence from = messageHelper.getSenderDisplayName(fromAddress);
|
||||
fromView.setText(from);
|
||||
|
||||
if (showStar) {
|
||||
mFlagged.setVisibility(View.VISIBLE);
|
||||
mFlagged.setChecked(message.isSet(Flag.FLAGGED));
|
||||
starView.setVisibility(View.VISIBLE);
|
||||
starView.setSelected(message.isSet(Flag.FLAGGED));
|
||||
} else {
|
||||
mFlagged.setVisibility(View.GONE);
|
||||
starView.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
mChip.setBackgroundColor(mAccount.getChipColor());
|
||||
|
||||
setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
public void setSubject(@NonNull String subject) {
|
||||
mSubjectView.setText(subject);
|
||||
mSubjectView.setTextColor(0xff000000 | defaultSubjectColor);
|
||||
}
|
||||
|
||||
public static boolean shouldShowSender(Message message) {
|
||||
Address[] from = message.getFrom();
|
||||
Address[] sender = message.getSender();
|
||||
|
||||
return sender != null && sender.length != 0 && !Arrays.equals(from, sender);
|
||||
subjectView.setText(subject);
|
||||
}
|
||||
|
||||
public void hideCryptoStatus() {
|
||||
mCryptoStatusIcon.setVisibility(View.GONE);
|
||||
cryptoStatusIcon.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
public void setCryptoStatusLoading() {
|
||||
|
@ -319,35 +180,10 @@ public class MessageHeader extends LinearLayout implements OnClickListener, OnLo
|
|||
|
||||
private void setCryptoDisplayStatus(MessageCryptoDisplayStatus displayStatus) {
|
||||
int color = ThemeUtils.getStyledColor(getContext(), displayStatus.getColorAttr());
|
||||
mCryptoStatusIcon.setEnabled(displayStatus.isEnabled());
|
||||
mCryptoStatusIcon.setVisibility(View.VISIBLE);
|
||||
mCryptoStatusIcon.setImageResource(displayStatus.getStatusIconRes());
|
||||
mCryptoStatusIcon.setColorFilter(color);
|
||||
}
|
||||
|
||||
private void updateAddressField(TextView v, CharSequence text, View label) {
|
||||
boolean hasText = !TextUtils.isEmpty(text);
|
||||
|
||||
v.setText(text);
|
||||
v.setVisibility(hasText ? View.VISIBLE : View.GONE);
|
||||
label.setVisibility(hasText ? View.VISIBLE : View.GONE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand or collapse a TextView by removing or adding the 2 lines limitation
|
||||
*/
|
||||
private void expand(TextView v, boolean expand) {
|
||||
if (expand) {
|
||||
v.setMaxLines(Integer.MAX_VALUE);
|
||||
v.setEllipsize(null);
|
||||
} else {
|
||||
v.setMaxLines(2);
|
||||
v.setEllipsize(android.text.TextUtils.TruncateAt.END);
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnCryptoClickListener(OnCryptoClickListener onCryptoClickListener) {
|
||||
this.onCryptoClickListener = onCryptoClickListener;
|
||||
cryptoStatusIcon.setEnabled(displayStatus.isEnabled());
|
||||
cryptoStatusIcon.setVisibility(View.VISIBLE);
|
||||
cryptoStatusIcon.setImageResource(displayStatus.getStatusIconRes());
|
||||
cryptoStatusIcon.setColorFilter(color);
|
||||
}
|
||||
|
||||
public void setOnMenuItemClickListener(OnMenuItemClickListener onMenuItemClickListener) {
|
||||
|
|
5
app/ui/legacy/src/main/res/drawable/btn_select_star.xml
Normal file
5
app/ui/legacy/src/main/res/drawable/btn_select_star.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_selected="true" android:drawable="@drawable/ic_star" />
|
||||
<item android:state_selected="false" android:drawable="@drawable/ic_star_border" />
|
||||
</selector>
|
10
app/ui/legacy/src/main/res/drawable/dots_vertical.xml
Normal file
10
app/ui/legacy/src/main/res/drawable/dots_vertical.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="?attr/colorControlNormal"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z" />
|
||||
</vector>
|
|
@ -1,297 +1,189 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<com.fsck.k9.view.MessageHeader
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<com.fsck.k9.view.MessageHeader 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/header_container"
|
||||
android:layout_width="match_parent"
|
||||
android:orientation="vertical"
|
||||
android:layout_height="wrap_content">
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/chip"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:clickable="false"
|
||||
android:textColor="@android:color/white"
|
||||
android:textSize="14sp"
|
||||
app:layout_constraintBottom_toTopOf="@+id/subject"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:chipBackgroundColor="#1976D2"
|
||||
tools:text="Account name" />
|
||||
|
||||
<com.fsck.k9.ui.helper.BottomBaselineTextView
|
||||
android:id="@+id/subject"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/chip"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="3"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="20sp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toStartOf="@+id/flagged"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
tools:text="Message subject" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/flagged"
|
||||
android:layout_width="44dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="?attr/controlBackground"
|
||||
android:baseline="33dp"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:src="@drawable/btn_select_star"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/subject"
|
||||
app:layout_constraintEnd_toEndOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:id="@+id/participants_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal" >
|
||||
android:background="?attr/colorPrimary"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:foreground="?attr/selectableItemBackground"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<!-- Color chip -->
|
||||
<View
|
||||
android:id="@+id/chip"
|
||||
android:layout_width="8dip"
|
||||
android:layout_height="match_parent"
|
||||
tools:background="#FF1976D2" />
|
||||
<de.hdodenhof.circleimageview.CircleImageView
|
||||
android:id="@+id/contact_picture"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_margin="16dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:src="@drawable/ic_contact_picture" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
<TextView
|
||||
android:id="@+id/from"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:ellipsize="end"
|
||||
android:gravity="center_vertical"
|
||||
android:maxLines="1"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body1"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintEnd_toStartOf="@+id/date"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toEndOf="@id/contact_picture"
|
||||
app:layout_constraintTop_toTopOf="@+id/contact_picture"
|
||||
tools:text="Sender name" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:padding="8dp"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:ellipsize="none"
|
||||
android:singleLine="true"
|
||||
android:text="Sep 19"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Caption"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
app:layout_constraintBaseline_toBaselineOf="@+id/from"
|
||||
app:layout_constraintEnd_toStartOf="@+id/menu_primary_action"
|
||||
app:layout_constraintStart_toEndOf="@id/from" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/subject"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="3"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textAppearance="@style/TextAppearance.K9.MediumSmall"
|
||||
tools:text="(no subject)"
|
||||
/>
|
||||
<ImageView
|
||||
android:id="@+id/crypto_status_icon"
|
||||
android:layout_width="18sp"
|
||||
android:layout_height="18sp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/to"
|
||||
app:layout_constraintStart_toEndOf="@id/contact_picture"
|
||||
app:srcCompat="@drawable/status_lock_disabled"
|
||||
app:tint="?attr/openpgp_grey"
|
||||
tools:visibility="visible" />
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/crypto_status_icon"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:padding="6dp"
|
||||
app:srcCompat="@drawable/status_lock_disabled"
|
||||
app:tint="?attr/openpgp_grey"
|
||||
android:background="?selectableItemBackground"
|
||||
android:visibility="gone"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/to"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="4dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:text="to me"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintEnd_toStartOf="@id/to_count"
|
||||
app:layout_constraintHorizontal_bias="0.0"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toEndOf="@id/crypto_status_icon"
|
||||
app:layout_constraintTop_toBottomOf="@+id/from"
|
||||
app:layout_goneMarginStart="16dp" />
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/flagged"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:focusable="false"
|
||||
android:checked="false"
|
||||
style="@style/MessageStarStyle"
|
||||
/>
|
||||
<TextView
|
||||
android:id="@+id/to_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginHorizontal="4dp"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_weight="1"
|
||||
android:singleLine="true"
|
||||
android:text="+2"
|
||||
android:textAppearance="@style/TextAppearance.MaterialComponents.Body2"
|
||||
android:textColor="?attr/colorAccent"
|
||||
app:layout_constraintBottom_toBottomOf="@+id/to"
|
||||
app:layout_constraintEnd_toStartOf="@+id/menu_primary_action"
|
||||
app:layout_constraintStart_toEndOf="@id/to" />
|
||||
|
||||
</LinearLayout>
|
||||
<ImageView
|
||||
android:id="@+id/menu_primary_action"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:background="?attr/controlBackground"
|
||||
android:paddingHorizontal="12dp"
|
||||
app:layout_constraintEnd_toStartOf="@id/menu_overflow"
|
||||
app:layout_constraintTop_toTopOf="@+id/menu_overflow"
|
||||
app:srcCompat="?iconActionSingleMessageOptions" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal" >
|
||||
<ImageView
|
||||
android:id="@+id/menu_overflow"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:background="?attr/controlBackground"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:paddingStart="6dp"
|
||||
android:paddingEnd="10dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/dots_vertical" />
|
||||
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<com.fsck.k9.ui.ContactBadge
|
||||
android:id="@+id/contact_badge"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
tools:src="@drawable/ic_contact_picture"/>
|
||||
|
||||
<!-- State icons -->
|
||||
<LinearLayout
|
||||
android:id="@+id/icon_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dip"
|
||||
android:layout_marginBottom="2dip"
|
||||
android:layout_below="@+id/contact_badge"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:orientation="vertical" >
|
||||
|
||||
<View
|
||||
android:id="@+id/answered"
|
||||
android:layout_width="32sp"
|
||||
android:layout_height="32sp"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingEnd="2dp"
|
||||
android:background="?attr/messageListAnswered" />
|
||||
|
||||
<View
|
||||
android:id="@+id/forwarded"
|
||||
android:layout_width="22sp"
|
||||
android:layout_height="22sp"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:background="?attr/messageListForwarded" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="6dip"
|
||||
android:layout_marginStart="2dp" >
|
||||
|
||||
<!-- From -->
|
||||
<TextView
|
||||
android:id="@+id/from"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_toStartOf="@+id/status_icon_strip"
|
||||
android:layout_alignBottom="@+id/status_icon_strip"
|
||||
android:paddingTop="0dp"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingEnd="6dp"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="end"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textAppearance="@style/TextAppearance.K9.MediumSmall"
|
||||
android:textStyle="bold"
|
||||
android:text="@string/general_no_sender"
|
||||
android:gravity="center_vertical"
|
||||
/>
|
||||
|
||||
<!-- Sender -->
|
||||
<TextView
|
||||
android:id="@+id/sender"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_toStartOf="@+id/status_icon_strip"
|
||||
android:paddingTop="0dp"
|
||||
android:layout_below="@+id/from"
|
||||
android:ellipsize="end"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textAppearance="@style/TextAppearance.K9.Small"
|
||||
android:textStyle="bold"
|
||||
android:visibility="gone"
|
||||
android:gravity="center_vertical"
|
||||
/>
|
||||
|
||||
<!-- To -->
|
||||
<TextView
|
||||
android:id="@+id/to_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignStart="@+id/from"
|
||||
android:layout_alignBaseline="@+id/to"
|
||||
android:paddingTop="2dp"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:text="@string/message_to_label"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textAppearance="@style/TextAppearance.K9.MediumSmall"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/to"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@+id/to_label"
|
||||
android:layout_below="@+id/sender"
|
||||
android:maxLines="2"
|
||||
android:ellipsize="end"
|
||||
android:paddingTop="2dp"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textAppearance="@style/TextAppearance.K9.MediumSmall" />
|
||||
|
||||
<!-- CC -->
|
||||
<TextView
|
||||
android:id="@+id/cc_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/to_label"
|
||||
android:layout_alignStart="@+id/to_label"
|
||||
android:layout_alignBaseline="@+id/cc"
|
||||
android:paddingTop="2dp"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:text="@string/message_view_cc_label"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textStyle="bold"
|
||||
android:textAppearance="@style/TextAppearance.K9.MediumSmall" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/cc"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@+id/cc_label"
|
||||
android:layout_below="@+id/to"
|
||||
android:maxLines="2"
|
||||
android:ellipsize="end"
|
||||
android:paddingTop="2dp"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textAppearance="@style/TextAppearance.K9.MediumSmall" />
|
||||
|
||||
<!-- BCC -->
|
||||
<TextView
|
||||
android:id="@+id/bcc_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@+id/cc_label"
|
||||
android:layout_alignStart="@+id/cc_label"
|
||||
android:layout_alignBaseline="@+id/bcc"
|
||||
android:paddingTop="2dp"
|
||||
android:paddingStart="0dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:text="@string/message_view_bcc_label"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textStyle="bold"
|
||||
android:textAppearance="@style/TextAppearance.K9.MediumSmall" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/bcc"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_toEndOf="@+id/bcc_label"
|
||||
android:layout_below="@+id/cc"
|
||||
android:maxLines="2"
|
||||
android:ellipsize="end"
|
||||
android:paddingTop="2dp"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textAppearance="@style/TextAppearance.K9.MediumSmall" />
|
||||
|
||||
<!-- Date -->
|
||||
<TextView
|
||||
android:id="@+id/date"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_below="@id/bcc"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:paddingTop="8dp"
|
||||
android:singleLine="true"
|
||||
android:ellipsize="none"
|
||||
android:textAppearance="@style/TextAppearance.K9.Small"
|
||||
android:textColor="?android:attr/textColorSecondary" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:id="@+id/status_icon_strip"
|
||||
>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon_single_message_options"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="?iconActionSingleMessageOptions"
|
||||
android:padding="8dp"
|
||||
android:background="?selectableItemBackground"
|
||||
/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<View
|
||||
android:layout_height="1dip"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_marginBottom="4dip"
|
||||
android:background="@drawable/divider_horizontal_email" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
</com.fsck.k9.view.MessageHeader>
|
||||
|
|
|
@ -1,35 +0,0 @@
|
|||
package com.fsck.k9.view
|
||||
|
||||
import com.fsck.k9.RobolectricTest
|
||||
import com.fsck.k9.mail.Address
|
||||
import com.fsck.k9.mail.internet.MimeMessage
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Test
|
||||
|
||||
class MessageHeaderTest : RobolectricTest() {
|
||||
|
||||
@Test
|
||||
fun shouldShowSender_withSender_shouldReturnTrue() {
|
||||
val message = createMessage("from@example1.com", "sender@example2.com")
|
||||
|
||||
val showSender = MessageHeader.shouldShowSender(message)
|
||||
|
||||
assertThat(showSender).isTrue()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun shouldShowSender_withoutSender_shouldReturnFalse() {
|
||||
val message = createMessage("from@example1.com")
|
||||
|
||||
val showSender = MessageHeader.shouldShowSender(message)
|
||||
|
||||
assertThat(showSender).isFalse()
|
||||
}
|
||||
|
||||
private fun createMessage(from: String, sender: String? = null) = MimeMessage().apply {
|
||||
setFrom(from.toAddress())
|
||||
setSender(sender?.toAddress())
|
||||
}
|
||||
|
||||
private fun String.toAddress() = Address.parse(this)[0]
|
||||
}
|
Loading…
Reference in a new issue