Browse Source

Added cc/bcc

main
M66B 6 years ago
parent
commit
774f9b3f36
53 changed files with 453 additions and 126 deletions
  1. +3
    -1
      app/src/main/java/eu/faircode/email/ActivityCompose.java
  2. +5
    -5
      app/src/main/java/eu/faircode/email/AdapterMessage.java
  3. +97
    -15
      app/src/main/java/eu/faircode/email/FragmentCompose.java
  4. +38
    -6
      app/src/main/java/eu/faircode/email/FragmentMessage.java
  5. +28
    -16
      app/src/main/java/eu/faircode/email/MessageHelper.java
  6. +4
    -4
      app/src/main/java/eu/faircode/email/ServiceSynchronize.java
  7. BIN
      app/src/main/res/drawable-hdpi/baseline_people_black_18.png
  8. BIN
      app/src/main/res/drawable-hdpi/baseline_people_black_24.png
  9. BIN
      app/src/main/res/drawable-hdpi/baseline_people_black_36.png
  10. BIN
      app/src/main/res/drawable-hdpi/baseline_people_black_48.png
  11. BIN
      app/src/main/res/drawable-hdpi/baseline_people_white_18.png
  12. BIN
      app/src/main/res/drawable-hdpi/baseline_people_white_24.png
  13. BIN
      app/src/main/res/drawable-hdpi/baseline_people_white_36.png
  14. BIN
      app/src/main/res/drawable-hdpi/baseline_people_white_48.png
  15. BIN
      app/src/main/res/drawable-mdpi/baseline_people_black_18.png
  16. BIN
      app/src/main/res/drawable-mdpi/baseline_people_black_24.png
  17. BIN
      app/src/main/res/drawable-mdpi/baseline_people_black_36.png
  18. BIN
      app/src/main/res/drawable-mdpi/baseline_people_black_48.png
  19. BIN
      app/src/main/res/drawable-mdpi/baseline_people_white_18.png
  20. BIN
      app/src/main/res/drawable-mdpi/baseline_people_white_24.png
  21. BIN
      app/src/main/res/drawable-mdpi/baseline_people_white_36.png
  22. BIN
      app/src/main/res/drawable-mdpi/baseline_people_white_48.png
  23. BIN
      app/src/main/res/drawable-xhdpi/baseline_people_black_18.png
  24. BIN
      app/src/main/res/drawable-xhdpi/baseline_people_black_24.png
  25. BIN
      app/src/main/res/drawable-xhdpi/baseline_people_black_36.png
  26. BIN
      app/src/main/res/drawable-xhdpi/baseline_people_black_48.png
  27. BIN
      app/src/main/res/drawable-xhdpi/baseline_people_white_18.png
  28. BIN
      app/src/main/res/drawable-xhdpi/baseline_people_white_24.png
  29. BIN
      app/src/main/res/drawable-xhdpi/baseline_people_white_36.png
  30. BIN
      app/src/main/res/drawable-xhdpi/baseline_people_white_48.png
  31. BIN
      app/src/main/res/drawable-xxhdpi/baseline_people_black_18.png
  32. BIN
      app/src/main/res/drawable-xxhdpi/baseline_people_black_24.png
  33. BIN
      app/src/main/res/drawable-xxhdpi/baseline_people_black_36.png
  34. BIN
      app/src/main/res/drawable-xxhdpi/baseline_people_black_48.png
  35. BIN
      app/src/main/res/drawable-xxhdpi/baseline_people_white_18.png
  36. BIN
      app/src/main/res/drawable-xxhdpi/baseline_people_white_24.png
  37. BIN
      app/src/main/res/drawable-xxhdpi/baseline_people_white_36.png
  38. BIN
      app/src/main/res/drawable-xxhdpi/baseline_people_white_48.png
  39. BIN
      app/src/main/res/drawable-xxxhdpi/baseline_people_black_18.png
  40. BIN
      app/src/main/res/drawable-xxxhdpi/baseline_people_black_24.png
  41. BIN
      app/src/main/res/drawable-xxxhdpi/baseline_people_black_36.png
  42. BIN
      app/src/main/res/drawable-xxxhdpi/baseline_people_black_48.png
  43. BIN
      app/src/main/res/drawable-xxxhdpi/baseline_people_white_18.png
  44. BIN
      app/src/main/res/drawable-xxxhdpi/baseline_people_white_24.png
  45. BIN
      app/src/main/res/drawable-xxxhdpi/baseline_people_white_36.png
  46. BIN
      app/src/main/res/drawable-xxxhdpi/baseline_people_white_48.png
  47. +10
    -0
      app/src/main/res/drawable/baseline_people_24.xml
  48. +64
    -5
      app/src/main/res/layout/fragment_compose.xml
  49. +139
    -7
      app/src/main/res/layout/fragment_message.xml
  50. +53
    -4
      app/src/main/res/layout/item_message.xml
  51. +0
    -63
      app/src/main/res/layout/message_header.xml
  52. +10
    -0
      app/src/main/res/menu/menu_cc.xml
  53. +2
    -0
      app/src/main/res/values/strings.xml

+ 3
- 1
app/src/main/java/eu/faircode/email/ActivityCompose.java View File

@ -28,7 +28,9 @@ public class ActivityCompose extends ActivityBase implements FragmentManager.OnB
static final int LOADER_COMPOSE_PUT = 2; static final int LOADER_COMPOSE_PUT = 2;
static final int LOADER_COMPOSE_DELETE = 3; static final int LOADER_COMPOSE_DELETE = 3;
static final int REQUEST_CONTACT = 1;
static final int REQUEST_CONTACT_TO = 1;
static final int REQUEST_CONTACT_CC = 2;
static final int REQUEST_CONTACT_BCC = 3;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {


+ 5
- 5
app/src/main/java/eu/faircode/email/AdapterMessage.java View File

@ -56,7 +56,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
public class ViewHolder extends RecyclerView.ViewHolder public class ViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener { implements View.OnClickListener {
View itemView; View itemView;
TextView tvAddress;
TextView tvFrom;
TextView tvTime; TextView tvTime;
TextView tvSubject; TextView tvSubject;
TextView tvCount; TextView tvCount;
@ -65,7 +65,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
super(itemView); super(itemView);
this.itemView = itemView; this.itemView = itemView;
tvAddress = itemView.findViewById(R.id.tvAddress);
tvFrom = itemView.findViewById(R.id.tvFrom);
tvTime = itemView.findViewById(R.id.tvTime); tvTime = itemView.findViewById(R.id.tvTime);
tvSubject = itemView.findViewById(R.id.tvSubject); tvSubject = itemView.findViewById(R.id.tvSubject);
tvCount = itemView.findViewById(R.id.tvCount); tvCount = itemView.findViewById(R.id.tvCount);
@ -220,10 +220,10 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
TupleMessageEx message = filtered.get(position); TupleMessageEx message = filtered.get(position);
if (EntityFolder.isOutgoing(message.folderType)) { if (EntityFolder.isOutgoing(message.folderType)) {
holder.tvAddress.setText(message.to == null ? null : MessageHelper.getFormattedAddresses(message.to));
holder.tvFrom.setText(MessageHelper.getFormattedAddresses(message.to));
holder.tvTime.setText(DateUtils.getRelativeTimeSpanString(context, message.received)); holder.tvTime.setText(DateUtils.getRelativeTimeSpanString(context, message.received));
} else { } else {
holder.tvAddress.setText(message.from == null ? null : MessageHelper.getFormattedAddresses(message.from));
holder.tvFrom.setText(MessageHelper.getFormattedAddresses(message.from));
holder.tvTime.setText(message.sent == null ? null : DateUtils.getRelativeTimeSpanString(context, message.sent)); holder.tvTime.setText(message.sent == null ? null : DateUtils.getRelativeTimeSpanString(context, message.sent));
} }
@ -236,7 +236,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
boolean unseen = (message.thread == null ? !message.seen : message.unseen > 0); boolean unseen = (message.thread == null ? !message.seen : message.unseen > 0);
int visibility = (unseen ? Typeface.BOLD : Typeface.NORMAL); int visibility = (unseen ? Typeface.BOLD : Typeface.NORMAL);
holder.tvAddress.setTypeface(null, visibility);
holder.tvFrom.setTypeface(null, visibility);
holder.tvTime.setTypeface(null, visibility); holder.tvTime.setTypeface(null, visibility);
holder.tvSubject.setTypeface(null, visibility); holder.tvSubject.setTypeface(null, visibility);
holder.tvCount.setTypeface(null, visibility); holder.tvCount.setTypeface(null, visibility);


+ 97
- 15
app/src/main/java/eu/faircode/email/FragmentCompose.java View File

@ -40,6 +40,8 @@ import android.text.TextUtils;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -69,13 +71,18 @@ public class FragmentCompose extends Fragment {
private long rid = -1; private long rid = -1;
private Spinner spFrom; private Spinner spFrom;
private ImageView ivIdentyAdd;
private ImageView ivIdentityAdd;
private EditText etTo; private EditText etTo;
private ImageView ivContactAdd;
private ImageView ivToAdd;
private EditText etCc;
private ImageView ivCcAdd;
private EditText etBcc;
private ImageView ivBccAdd;
private EditText etSubject; private EditText etSubject;
private EditText etBody; private EditText etBody;
private BottomNavigationView bottom_navigation; private BottomNavigationView bottom_navigation;
private ProgressBar pbWait; private ProgressBar pbWait;
private Group grpCc;
private Group grpReady; private Group grpReady;
@Override @Override
@ -90,20 +97,26 @@ public class FragmentCompose extends Fragment {
// Get controls // Get controls
spFrom = view.findViewById(R.id.spFrom); spFrom = view.findViewById(R.id.spFrom);
ivIdentyAdd = view.findViewById(R.id.ivIdentyAdd);
ivIdentityAdd = view.findViewById(R.id.ivIdentityAdd);
etTo = view.findViewById(R.id.etTo); etTo = view.findViewById(R.id.etTo);
ivContactAdd = view.findViewById(R.id.ivContactAdd);
ivToAdd = view.findViewById(R.id.ivToAdd);
etCc = view.findViewById(R.id.etCc);
ivCcAdd = view.findViewById(R.id.ivCcAdd);
etBcc = view.findViewById(R.id.etBcc);
ivBccAdd = view.findViewById(R.id.ivBccAdd);
etSubject = view.findViewById(R.id.etSubject); etSubject = view.findViewById(R.id.etSubject);
etBody = view.findViewById(R.id.etBody); etBody = view.findViewById(R.id.etBody);
bottom_navigation = view.findViewById(R.id.bottom_navigation); bottom_navigation = view.findViewById(R.id.bottom_navigation);
pbWait = view.findViewById(R.id.pbWait); pbWait = view.findViewById(R.id.pbWait);
grpCc = view.findViewById(R.id.grpCc);
grpReady = view.findViewById(R.id.grpReady); grpReady = view.findViewById(R.id.grpReady);
grpCc.setVisibility(View.GONE);
etBody.setMovementMethod(LinkMovementMethod.getInstance()); etBody.setMovementMethod(LinkMovementMethod.getInstance());
// Wire controls // Wire controls
ivIdentyAdd.setOnClickListener(new View.OnClickListener() {
ivIdentityAdd.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
Bundle args = new Bundle(); Bundle args = new Bundle();
@ -116,11 +129,27 @@ public class FragmentCompose extends Fragment {
} }
}); });
ivContactAdd.setOnClickListener(new View.OnClickListener() {
ivToAdd.setOnClickListener(new View.OnClickListener() {
@Override @Override
public void onClick(View view) { public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Email.CONTENT_URI); Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Email.CONTENT_URI);
startActivityForResult(intent, ActivityCompose.REQUEST_CONTACT);
startActivityForResult(intent, ActivityCompose.REQUEST_CONTACT_TO);
}
});
ivCcAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Email.CONTENT_URI);
startActivityForResult(intent, ActivityCompose.REQUEST_CONTACT_CC);
}
});
ivBccAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Intent intent = new Intent(Intent.ACTION_PICK, ContactsContract.CommonDataKinds.Email.CONTENT_URI);
startActivityForResult(intent, ActivityCompose.REQUEST_CONTACT_BCC);
} }
}); });
@ -145,6 +174,8 @@ public class FragmentCompose extends Fragment {
} }
}); });
setHasOptionsMenu(true);
// Initialize // Initialize
grpReady.setVisibility(View.GONE); grpReady.setVisibility(View.GONE);
pbWait.setVisibility(View.VISIBLE); pbWait.setVisibility(View.VISIBLE);
@ -185,9 +216,30 @@ public class FragmentCompose extends Fragment {
((AppCompatActivity) getActivity()).getSupportActionBar().setSubtitle(R.string.title_compose); ((AppCompatActivity) getActivity()).getSupportActionBar().setSubtitle(R.string.title_compose);
} }
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_cc, menu);
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_cc:
onMenuCc();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void onMenuCc() {
grpCc.setVisibility(grpCc.getVisibility() == View.GONE ? View.VISIBLE : View.GONE);
}
@Override @Override
public void onActivityResult(int requestCode, int resultCode, Intent data) { public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == ActivityCompose.REQUEST_CONTACT && resultCode == RESULT_OK) {
if (resultCode == RESULT_OK) {
Cursor cursor = null; Cursor cursor = null;
try { try {
cursor = getContext().getContentResolver().query(data.getData(), cursor = getContext().getContentResolver().query(data.getData(),
@ -202,12 +254,26 @@ public class FragmentCompose extends Fragment {
String email = cursor.getString(colEmail); String email = cursor.getString(colEmail);
String name = cursor.getString(colName); String name = cursor.getString(colName);
String text = null;
if (requestCode == ActivityCompose.REQUEST_CONTACT_TO)
text = etTo.getText().toString();
else if (requestCode == ActivityCompose.REQUEST_CONTACT_CC)
text = etCc.getText().toString();
else if (requestCode == ActivityCompose.REQUEST_CONTACT_BCC)
text = etBcc.getText().toString();
InternetAddress address = new InternetAddress(email, name); InternetAddress address = new InternetAddress(email, name);
StringBuilder sb = new StringBuilder(etTo.getText().toString());
StringBuilder sb = new StringBuilder(text);
if (sb.length() > 0) if (sb.length() > 0)
sb.append("; "); sb.append("; ");
sb.append(address.toString()); sb.append(address.toString());
etTo.setText(sb.toString());
if (requestCode == ActivityCompose.REQUEST_CONTACT_TO)
etTo.setText(sb.toString());
else if (requestCode == ActivityCompose.REQUEST_CONTACT_CC)
etCc.setText(sb.toString());
else if (requestCode == ActivityCompose.REQUEST_CONTACT_BCC)
etBcc.setText(sb.toString());
} }
} catch (Throwable ex) { } catch (Throwable ex) {
Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex)); Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex));
@ -236,6 +302,8 @@ public class FragmentCompose extends Fragment {
args.putString("thread", FragmentCompose.this.thread); args.putString("thread", FragmentCompose.this.thread);
args.putLong("rid", FragmentCompose.this.rid); args.putLong("rid", FragmentCompose.this.rid);
args.putString("to", etTo.getText().toString()); args.putString("to", etTo.getText().toString());
args.putString("cc", etCc.getText().toString());
args.putString("bcc", etBcc.getText().toString());
args.putString("subject", etSubject.getText().toString()); args.putString("subject", etSubject.getText().toString());
args.putString("body", etBody.getText().toString()); args.putString("body", etBody.getText().toString());
args.putBoolean("send", send); args.putBoolean("send", send);
@ -270,6 +338,8 @@ public class FragmentCompose extends Fragment {
result.putLong("iid", msg.identity); result.putLong("iid", msg.identity);
if (msg.replying != null) if (msg.replying != null)
result.putLong("rid", msg.replying); result.putLong("rid", msg.replying);
result.putString("cc", msg.cc);
result.putString("bcc", msg.bcc);
result.putString("thread", msg.thread); result.putString("thread", msg.thread);
result.putString("subject", msg.subject); result.putString("subject", msg.subject);
result.putString("body", msg.body); result.putString("body", msg.body);
@ -339,6 +409,8 @@ public class FragmentCompose extends Fragment {
String thread = result.getString("thread"); String thread = result.getString("thread");
String from = result.getString("from"); String from = result.getString("from");
String to = result.getString("to"); String to = result.getString("to");
String cc = result.getString("cc");
String bcc = result.getString("bcc");
String subject = result.getString("subject"); String subject = result.getString("subject");
String body = result.getString("body"); String body = result.getString("body");
String action = result.getString("action"); String action = result.getString("action");
@ -363,9 +435,11 @@ public class FragmentCompose extends Fragment {
// Prevent changed fields from being overwritten // Prevent changed fields from being overwritten
once = true; once = true;
etCc.setText(TextUtils.join(", ", MessageHelper.decodeAddresses(cc)));
etBcc.setText(TextUtils.join(", ", MessageHelper.decodeAddresses(bcc)));
if (action == null) { if (action == null) {
if (to != null)
etTo.setText(TextUtils.join(", ", MessageHelper.decodeAddresses(to)));
etTo.setText(TextUtils.join(", ", MessageHelper.decodeAddresses(to)));
etSubject.setText(subject); etSubject.setText(subject);
if (body != null) if (body != null)
etBody.setText(Html.fromHtml(HtmlHelper.sanitize(getContext(), body, false))); etBody.setText(Html.fromHtml(HtmlHelper.sanitize(getContext(), body, false)));
@ -480,11 +554,15 @@ public class FragmentCompose extends Fragment {
long rid = args.getLong("rid", -1); long rid = args.getLong("rid", -1);
String thread = args.getString("thread"); String thread = args.getString("thread");
String to = args.getString("to"); String to = args.getString("to");
String cc = args.getString("cc");
String bcc = args.getString("bcc");
String body = args.getString("body"); String body = args.getString("body");
String subject = args.getString("subject"); String subject = args.getString("subject");
Address afrom = (ident == null ? null : new InternetAddress(ident.email, ident.name)); Address afrom = (ident == null ? null : new InternetAddress(ident.email, ident.name));
Address ato[] = (TextUtils.isEmpty(to) ? null : InternetAddress.parse(to)); Address ato[] = (TextUtils.isEmpty(to) ? null : InternetAddress.parse(to));
Address acc[] = (TextUtils.isEmpty(cc) ? null : InternetAddress.parse(cc));
Address abcc[] = (TextUtils.isEmpty(bcc) ? null : InternetAddress.parse(bcc));
// Build draft // Build draft
boolean update = (draft != null); boolean update = (draft != null);
@ -495,8 +573,10 @@ public class FragmentCompose extends Fragment {
draft.identity = (ident == null ? null : ident.id); draft.identity = (ident == null ? null : ident.id);
draft.replying = (rid < 0 ? null : rid); draft.replying = (rid < 0 ? null : rid);
draft.thread = thread; draft.thread = thread;
draft.from = (afrom == null ? null : MessageHelper.encodeAddresses(new Address[]{afrom}));
draft.to = (ato == null ? null : MessageHelper.encodeAddresses(ato));
draft.from = MessageHelper.encodeAddresses(new Address[]{afrom});
draft.to = MessageHelper.encodeAddresses(ato);
draft.cc = MessageHelper.encodeAddresses(acc);
draft.bcc = MessageHelper.encodeAddresses(abcc);
draft.subject = subject; draft.subject = subject;
draft.body = "<pre>" + body.replaceAll("\\r?\\n", "<br />") + "</pre>"; draft.body = "<pre>" + body.replaceAll("\\r?\\n", "<br />") + "</pre>";
draft.received = new Date().getTime(); draft.received = new Date().getTime();
@ -514,7 +594,7 @@ public class FragmentCompose extends Fragment {
if (send) { if (send) {
if (draft.identity == null) if (draft.identity == null)
throw new MessagingException(getContext().getString(R.string.title_from_missing)); throw new MessagingException(getContext().getString(R.string.title_from_missing));
if (draft.to == null)
if (draft.to == null && draft.cc == null && draft.bcc == null)
throw new MessagingException(getContext().getString(R.string.title_to_missing)); throw new MessagingException(getContext().getString(R.string.title_to_missing));
// Get outbox // Get outbox
@ -536,6 +616,8 @@ public class FragmentCompose extends Fragment {
out.thread = draft.thread; out.thread = draft.thread;
out.from = draft.from; out.from = draft.from;
out.to = draft.to; out.to = draft.to;
out.cc = draft.cc;
out.bcc = draft.bcc;
out.subject = draft.subject; out.subject = draft.subject;
out.body = draft.body; out.body = draft.body;
out.received = draft.received; out.received = draft.received;


+ 38
- 6
app/src/main/java/eu/faircode/email/FragmentMessage.java View File

@ -37,6 +37,8 @@ import android.text.Html;
import android.text.method.LinkMovementMethod; import android.text.method.LinkMovementMethod;
import android.util.Log; import android.util.Log;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem; import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
@ -53,12 +55,16 @@ import java.util.concurrent.Executors;
public class FragmentMessage extends Fragment { public class FragmentMessage extends Fragment {
private TextView tvTime; private TextView tvTime;
private TextView tvFrom; private TextView tvFrom;
private TextView tvTo;
private TextView tvCc;
private TextView tvBcc;
private TextView tvSubject; private TextView tvSubject;
private TextView tvCount; private TextView tvCount;
private BottomNavigationView top_navigation; private BottomNavigationView top_navigation;
private TextView tvBody; private TextView tvBody;
private BottomNavigationView bottom_navigation; private BottomNavigationView bottom_navigation;
private ProgressBar pbWait; private ProgressBar pbWait;
private Group grpCc;
private Group grpReady; private Group grpReady;
private LiveData<TupleFolderEx> liveFolder; private LiveData<TupleFolderEx> liveFolder;
@ -77,7 +83,10 @@ public class FragmentMessage extends Fragment {
final long id = args.getLong("id"); final long id = args.getLong("id");
// Get controls // Get controls
tvFrom = view.findViewById(R.id.tvAddress);
tvFrom = view.findViewById(R.id.tvFrom);
tvTo = view.findViewById(R.id.tvTo);
tvCc = view.findViewById(R.id.tvCc);
tvBcc = view.findViewById(R.id.tvBcc);
tvTime = view.findViewById(R.id.tvTime); tvTime = view.findViewById(R.id.tvTime);
tvSubject = view.findViewById(R.id.tvSubject); tvSubject = view.findViewById(R.id.tvSubject);
tvCount = view.findViewById(R.id.tvCount); tvCount = view.findViewById(R.id.tvCount);
@ -85,12 +94,10 @@ public class FragmentMessage extends Fragment {
tvBody = view.findViewById(R.id.tvBody); tvBody = view.findViewById(R.id.tvBody);
bottom_navigation = view.findViewById(R.id.bottom_navigation); bottom_navigation = view.findViewById(R.id.bottom_navigation);
pbWait = view.findViewById(R.id.pbWait); pbWait = view.findViewById(R.id.pbWait);
grpCc = view.findViewById(R.id.grpCc);
grpReady = view.findViewById(R.id.grpReady); grpReady = view.findViewById(R.id.grpReady);
tvTime.setTextIsSelectable(true);
tvFrom.setTextIsSelectable(true);
tvSubject.setTextIsSelectable(true);
tvBody.setTextIsSelectable(true);
setHasOptionsMenu(true);
tvBody.setMovementMethod(LinkMovementMethod.getInstance()); tvBody.setMovementMethod(LinkMovementMethod.getInstance());
// Wire controls // Wire controls
@ -141,6 +148,7 @@ public class FragmentMessage extends Fragment {
}); });
// Initialize // Initialize
grpCc.setVisibility(View.GONE);
grpReady.setVisibility(View.GONE); grpReady.setVisibility(View.GONE);
pbWait.setVisibility(View.VISIBLE); pbWait.setVisibility(View.VISIBLE);
@ -161,7 +169,10 @@ public class FragmentMessage extends Fragment {
if (FragmentMessage.this.isVisible()) if (FragmentMessage.this.isVisible())
getFragmentManager().popBackStack(); getFragmentManager().popBackStack();
} else { } else {
tvFrom.setText(message.from == null ? null : MessageHelper.getFormattedAddresses(message.from));
tvFrom.setText(MessageHelper.getFormattedAddresses(message.from));
tvTo.setText(MessageHelper.getFormattedAddresses(message.to));
tvCc.setText(MessageHelper.getFormattedAddresses(message.cc));
tvBcc.setText(MessageHelper.getFormattedAddresses(message.bcc));
tvTime.setText(message.sent == null ? null : df.format(new Date(message.sent))); tvTime.setText(message.sent == null ? null : df.format(new Date(message.sent)));
tvSubject.setText(message.subject); tvSubject.setText(message.subject);
tvCount.setText(Integer.toString(message.count)); tvCount.setText(Integer.toString(message.count));
@ -203,6 +214,27 @@ public class FragmentMessage extends Fragment {
liveFolder.removeObservers(this); liveFolder.removeObservers(this);
} }
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_cc, menu);
super.onCreateOptionsMenu(menu, inflater);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_cc:
onMenuCc();
return true;
default:
return super.onOptionsItemSelected(item);
}
}
private void onMenuCc() {
grpCc.setVisibility(grpCc.getVisibility() == View.GONE ? View.VISIBLE : View.GONE);
}
Observer<TupleFolderEx> folderObserver = new Observer<TupleFolderEx>() { Observer<TupleFolderEx> folderObserver = new Observer<TupleFolderEx>() {
@Override @Override
public void onChanged(@Nullable TupleFolderEx folder) { public void onChanged(@Nullable TupleFolderEx folder) {


+ 28
- 16
app/src/main/java/eu/faircode/email/MessageHelper.java View File

@ -90,7 +90,10 @@ public class MessageHelper {
imessage.setRecipients(Message.RecipientType.TO, MessageHelper.decodeAddresses(message.to)); imessage.setRecipients(Message.RecipientType.TO, MessageHelper.decodeAddresses(message.to));
if (message.cc != null) if (message.cc != null)
imessage.setRecipients(Message.RecipientType.CC, MessageHelper.decodeAddresses(message.to));
imessage.setRecipients(Message.RecipientType.CC, MessageHelper.decodeAddresses(message.cc));
if (message.bcc != null)
imessage.setRecipients(Message.RecipientType.BCC, MessageHelper.decodeAddresses(message.bcc));
if (message.subject != null) if (message.subject != null)
imessage.setSubject(message.subject); imessage.setSubject(message.subject);
@ -153,11 +156,17 @@ public class MessageHelper {
return encodeAddresses(imessage.getRecipients(Message.RecipientType.CC)); return encodeAddresses(imessage.getRecipients(Message.RecipientType.CC));
} }
String getBcc() throws MessagingException, JSONException {
return encodeAddresses(imessage.getRecipients(Message.RecipientType.BCC));
}
String getReply() throws MessagingException, JSONException { String getReply() throws MessagingException, JSONException {
return encodeAddresses(imessage.getReplyTo()); return encodeAddresses(imessage.getReplyTo());
} }
static String encodeAddresses(Address[] addresses) throws JSONException { static String encodeAddresses(Address[] addresses) throws JSONException {
if (addresses == null)
return null;
JSONArray jaddresses = new JSONArray(); JSONArray jaddresses = new JSONArray();
if (addresses != null) if (addresses != null)
for (Address address : addresses) for (Address address : addresses)
@ -175,23 +184,24 @@ public class MessageHelper {
} }
static Address[] decodeAddresses(String json) { static Address[] decodeAddresses(String json) {
if (json == null)
return new Address[0];
List<Address> result = new ArrayList<>(); List<Address> result = new ArrayList<>();
if (json != null)
try {
JSONArray jaddresses = new JSONArray(json);
for (int i = 0; i < jaddresses.length(); i++) {
JSONObject jaddress = (JSONObject) jaddresses.get(i);
if (jaddress.has("personal"))
result.add(new InternetAddress(
jaddress.getString("address"),
jaddress.getString("personal")));
else
result.add(new InternetAddress(
jaddress.getString("address")));
}
} catch (Throwable ex) {
Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex));
try {
JSONArray jaddresses = new JSONArray(json);
for (int i = 0; i < jaddresses.length(); i++) {
JSONObject jaddress = (JSONObject) jaddresses.get(i);
if (jaddress.has("personal"))
result.add(new InternetAddress(
jaddress.getString("address"),
jaddress.getString("personal")));
else
result.add(new InternetAddress(
jaddress.getString("address")));
} }
} catch (Throwable ex) {
Log.e(Helper.TAG, ex + "\n" + Log.getStackTraceString(ex));
}
return result.toArray(new Address[0]); return result.toArray(new Address[0]);
} }
@ -200,6 +210,8 @@ public class MessageHelper {
} }
static String getFormattedAddresses(String json) { static String getFormattedAddresses(String json) {
if (json == null)
return null;
try { try {
List<String> addresses = new ArrayList<>(); List<String> addresses = new ArrayList<>();
for (Address address : decodeAddresses(json)) for (Address address : decodeAddresses(json))


+ 4
- 4
app/src/main/java/eu/faircode/email/ServiceSynchronize.java View File

@ -639,7 +639,7 @@ public class ServiceSynchronize extends LifecycleService {
try { try {
itransport.connect(ident.host, ident.port, ident.user, ident.password); itransport.connect(ident.host, ident.port, ident.user, ident.password);
Address[] to = imessage.getRecipients(Message.RecipientType.TO);
Address[] to = imessage.getAllRecipients();
itransport.sendMessage(imessage, to); itransport.sendMessage(imessage, to);
Log.i(Helper.TAG, "Sent via " + ident.host + "/" + ident.user + Log.i(Helper.TAG, "Sent via " + ident.host + "/" + ident.user +
" to " + TextUtils.join(", ", to)); " to " + TextUtils.join(", ", to));
@ -680,14 +680,14 @@ public class ServiceSynchronize extends LifecycleService {
names.add(folder.name); names.add(folder.name);
Log.i(Helper.TAG, "Local folder count=" + names.size()); Log.i(Helper.TAG, "Local folder count=" + names.size());
Folder[] ifolders = istore.getDefaultFolder().list("*");
Folder[] ifolders = istore.getDefaultFolder().list("*"); // TODO: is the pattern correct?
Log.i(Helper.TAG, "Remote folder count=" + ifolders.length); Log.i(Helper.TAG, "Remote folder count=" + ifolders.length);
for (Folder ifolder : ifolders) { for (Folder ifolder : ifolders) {
String[] attrs = ((IMAPFolder) ifolder).getAttributes(); String[] attrs = ((IMAPFolder) ifolder).getAttributes();
boolean candidate = true; boolean candidate = true;
for (String attr : attrs) { for (String attr : attrs) {
if ("\\Noselect".equals(attr)) {
if ("\\Noselect".equals(attr)) { // TODO: is this attribute correct?
candidate = false; candidate = false;
break; break;
} }
@ -844,7 +844,7 @@ public class ServiceSynchronize extends LifecycleService {
message.from = helper.getFrom(); message.from = helper.getFrom();
message.to = helper.getTo(); message.to = helper.getTo();
message.cc = helper.getCc(); message.cc = helper.getCc();
message.bcc = null;
message.bcc = helper.getBcc();
message.reply = helper.getReply(); message.reply = helper.getReply();
message.subject = imessage.getSubject(); message.subject = imessage.getSubject();
message.body = helper.getHtml(); message.body = helper.getHtml();


BIN
app/src/main/res/drawable-hdpi/baseline_people_black_18.png View File

Before After
Width: 27  |  Height: 27  |  Size: 247 B

BIN
app/src/main/res/drawable-hdpi/baseline_people_black_24.png View File

Before After
Width: 36  |  Height: 36  |  Size: 260 B

BIN
app/src/main/res/drawable-hdpi/baseline_people_black_36.png View File

Before After
Width: 54  |  Height: 54  |  Size: 355 B

BIN
app/src/main/res/drawable-hdpi/baseline_people_black_48.png View File

Before After
Width: 72  |  Height: 72  |  Size: 430 B

BIN
app/src/main/res/drawable-hdpi/baseline_people_white_18.png View File

Before After
Width: 27  |  Height: 27  |  Size: 249 B

BIN
app/src/main/res/drawable-hdpi/baseline_people_white_24.png View File

Before After
Width: 36  |  Height: 36  |  Size: 260 B

BIN
app/src/main/res/drawable-hdpi/baseline_people_white_36.png View File

Before After
Width: 54  |  Height: 54  |  Size: 353 B

BIN
app/src/main/res/drawable-hdpi/baseline_people_white_48.png View File

Before After
Width: 72  |  Height: 72  |  Size: 425 B

BIN
app/src/main/res/drawable-mdpi/baseline_people_black_18.png View File

Before After
Width: 18  |  Height: 18  |  Size: 156 B

BIN
app/src/main/res/drawable-mdpi/baseline_people_black_24.png View File

Before After
Width: 24  |  Height: 24  |  Size: 184 B

BIN
app/src/main/res/drawable-mdpi/baseline_people_black_36.png View File

Before After
Width: 36  |  Height: 36  |  Size: 260 B

BIN
app/src/main/res/drawable-mdpi/baseline_people_black_48.png View File

Before After
Width: 48  |  Height: 48  |  Size: 317 B

BIN
app/src/main/res/drawable-mdpi/baseline_people_white_18.png View File

Before After
Width: 18  |  Height: 18  |  Size: 159 B

BIN
app/src/main/res/drawable-mdpi/baseline_people_white_24.png View File

Before After
Width: 24  |  Height: 24  |  Size: 187 B

BIN
app/src/main/res/drawable-mdpi/baseline_people_white_36.png View File

Before After
Width: 36  |  Height: 36  |  Size: 260 B

BIN
app/src/main/res/drawable-mdpi/baseline_people_white_48.png View File

Before After
Width: 48  |  Height: 48  |  Size: 313 B

BIN
app/src/main/res/drawable-xhdpi/baseline_people_black_18.png View File

Before After
Width: 36  |  Height: 36  |  Size: 260 B

BIN
app/src/main/res/drawable-xhdpi/baseline_people_black_24.png View File

Before After
Width: 48  |  Height: 48  |  Size: 317 B

BIN
app/src/main/res/drawable-xhdpi/baseline_people_black_36.png View File

Before After
Width: 72  |  Height: 72  |  Size: 430 B

BIN
app/src/main/res/drawable-xhdpi/baseline_people_black_48.png View File

Before After
Width: 96  |  Height: 96  |  Size: 567 B

BIN
app/src/main/res/drawable-xhdpi/baseline_people_white_18.png View File

Before After
Width: 36  |  Height: 36  |  Size: 260 B

BIN
app/src/main/res/drawable-xhdpi/baseline_people_white_24.png View File

Before After
Width: 48  |  Height: 48  |  Size: 313 B

BIN
app/src/main/res/drawable-xhdpi/baseline_people_white_36.png View File

Before After
Width: 72  |  Height: 72  |  Size: 425 B

BIN
app/src/main/res/drawable-xhdpi/baseline_people_white_48.png View File

Before After
Width: 96  |  Height: 96  |  Size: 554 B

BIN
app/src/main/res/drawable-xxhdpi/baseline_people_black_18.png View File

Before After
Width: 54  |  Height: 54  |  Size: 355 B

BIN
app/src/main/res/drawable-xxhdpi/baseline_people_black_24.png View File

Before After
Width: 72  |  Height: 72  |  Size: 430 B

BIN
app/src/main/res/drawable-xxhdpi/baseline_people_black_36.png View File

Before After
Width: 108  |  Height: 108  |  Size: 637 B

BIN
app/src/main/res/drawable-xxhdpi/baseline_people_black_48.png View File

Before After
Width: 144  |  Height: 144  |  Size: 838 B

BIN
app/src/main/res/drawable-xxhdpi/baseline_people_white_18.png View File

Before After
Width: 54  |  Height: 54  |  Size: 353 B

BIN
app/src/main/res/drawable-xxhdpi/baseline_people_white_24.png View File

Before After
Width: 72  |  Height: 72  |  Size: 425 B

BIN
app/src/main/res/drawable-xxhdpi/baseline_people_white_36.png View File

Before After
Width: 108  |  Height: 108  |  Size: 632 B

BIN
app/src/main/res/drawable-xxhdpi/baseline_people_white_48.png View File

Before After
Width: 144  |  Height: 144  |  Size: 827 B

BIN
app/src/main/res/drawable-xxxhdpi/baseline_people_black_18.png View File

Before After
Width: 72  |  Height: 72  |  Size: 430 B

BIN
app/src/main/res/drawable-xxxhdpi/baseline_people_black_24.png View File

Before After
Width: 96  |  Height: 96  |  Size: 567 B

BIN
app/src/main/res/drawable-xxxhdpi/baseline_people_black_36.png View File

Before After
Width: 144  |  Height: 144  |  Size: 838 B

BIN
app/src/main/res/drawable-xxxhdpi/baseline_people_black_48.png View File

Before After
Width: 192  |  Height: 192  |  Size: 1.1 KiB

BIN
app/src/main/res/drawable-xxxhdpi/baseline_people_white_18.png View File

Before After
Width: 72  |  Height: 72  |  Size: 425 B

BIN
app/src/main/res/drawable-xxxhdpi/baseline_people_white_24.png View File

Before After
Width: 96  |  Height: 96  |  Size: 554 B

BIN
app/src/main/res/drawable-xxxhdpi/baseline_people_white_36.png View File

Before After
Width: 144  |  Height: 144  |  Size: 827 B

BIN
app/src/main/res/drawable-xxxhdpi/baseline_people_white_48.png View File

Before After
Width: 192  |  Height: 192  |  Size: 1.1 KiB

+ 10
- 0
app/src/main/res/drawable/baseline_people_24.xml View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24.0"
android:viewportHeight="24.0"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M16,11c1.66,0 2.99,-1.34 2.99,-3S17.66,5 16,5c-1.66,0 -3,1.34 -3,3s1.34,3 3,3zM8,11c1.66,0 2.99,-1.34 2.99,-3S9.66,5 8,5C6.34,5 5,6.34 5,8s1.34,3 3,3zM8,13c-2.33,0 -7,1.17 -7,3.5L1,19h14v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5zM16,13c-0.29,0 -0.62,0.02 -0.97,0.05 1.16,0.84 1.97,1.97 1.97,3.45L17,19h6v-2.5c0,-2.33 -4.67,-3.5 -7,-3.5z"/>
</vector>

+ 64
- 5
app/src/main/res/layout/fragment_compose.xml View File

@ -14,11 +14,13 @@
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<ImageView <ImageView
android:id="@+id/ivIdentyAdd"
android:id="@+id/ivIdentityAdd"
android:layout_width="24dp" android:layout_width="24dp"
android:layout_height="24dp" android:layout_height="24dp"
android:layout_marginEnd="6dp"
android:layout_marginStart="6dp" android:layout_marginStart="6dp"
android:src="@drawable/baseline_person_add_24" android:src="@drawable/baseline_person_add_24"
app:layout_constraintBottom_toBottomOf="@id/spFrom"
app:layout_constraintStart_toEndOf="@id/spFrom" app:layout_constraintStart_toEndOf="@id/spFrom"
app:layout_constraintTop_toTopOf="@id/spFrom" /> app:layout_constraintTop_toTopOf="@id/spFrom" />
@ -31,21 +33,72 @@
android:inputType="textEmailAddress" android:inputType="textEmailAddress"
android:maxLines="1" android:maxLines="1"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintEnd_toStartOf="@+id/ivContactAdd"
app:layout_constraintEnd_toStartOf="@+id/ivToAdd"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/spFrom" /> app:layout_constraintTop_toBottomOf="@+id/spFrom" />
<ImageView <ImageView
android:id="@+id/ivContactAdd"
android:id="@+id/ivToAdd"
android:layout_width="24dp" android:layout_width="24dp"
android:layout_height="24dp" android:layout_height="24dp"
android:layout_marginEnd="6dp" android:layout_marginEnd="6dp"
android:layout_marginStart="6dp" android:layout_marginStart="6dp"
android:src="@drawable/baseline_person_24" android:src="@drawable/baseline_person_24"
app:layout_constraintBottom_toBottomOf="@id/etTo"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/etTo" app:layout_constraintStart_toEndOf="@id/etTo"
app:layout_constraintTop_toTopOf="@+id/etTo" /> app:layout_constraintTop_toTopOf="@+id/etTo" />
<EditText
android:id="@+id/etCc"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:hint="@string/title_cc"
android:inputType="textEmailAddress"
android:maxLines="1"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintEnd_toStartOf="@+id/ivCcAdd"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etTo" />
<ImageView
android:id="@+id/ivCcAdd"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="6dp"
android:layout_marginStart="6dp"
android:src="@drawable/baseline_person_24"
app:layout_constraintBottom_toBottomOf="@id/etCc"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/etCc"
app:layout_constraintTop_toTopOf="@+id/etCc" />
<EditText
android:id="@+id/etBcc"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:hint="@string/title_bcc"
android:inputType="textEmailAddress"
android:maxLines="1"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintEnd_toStartOf="@+id/ivBccAdd"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etCc" />
<ImageView
android:id="@+id/ivBccAdd"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="6dp"
android:layout_marginStart="6dp"
android:src="@drawable/baseline_person_24"
app:layout_constraintBottom_toBottomOf="@id/etBcc"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/etBcc"
app:layout_constraintTop_toTopOf="@+id/etBcc" />
<EditText <EditText
android:id="@+id/etSubject" android:id="@+id/etSubject"
android:layout_width="0dp" android:layout_width="0dp"
@ -58,7 +111,7 @@
android:textAppearance="@style/TextAppearance.AppCompat.Medium" android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etTo" />
app:layout_constraintTop_toBottomOf="@+id/etBcc" />
<View <View
android:id="@+id/vSeparator" android:id="@+id/vSeparator"
@ -117,9 +170,15 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent" /> app:layout_constraintTop_toBottomOf="parent" />
<android.support.constraint.Group
android:id="@+id/grpCc"
android:layout_width="0dp"
android:layout_height="0dp"
app:constraint_referenced_ids="etCc,ivCcAdd,etBcc,ivBccAdd" />
<android.support.constraint.Group <android.support.constraint.Group
android:id="@+id/grpReady" android:id="@+id/grpReady"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
app:constraint_referenced_ids="spFrom,ivIdentyAdd,etTo,etSubject,vSeparator,scroll,bottom_navigation" />
app:constraint_referenced_ids="spFrom,ivIdentityAdd,etTo,etSubject,vSeparator,scroll,bottom_navigation" />
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>

+ 139
- 7
app/src/main/res/layout/fragment_message.xml View File

@ -7,14 +7,139 @@
android:orientation="vertical" android:orientation="vertical"
tools:context=".ActivityView"> tools:context=".ActivityView">
<include
android:id="@+id/include"
layout="@layout/message_header"
android:layout_width="match_parent"
<TextView
android:id="@+id/tvFrom"
android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:layout_marginStart="6dp"
android:text="From"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textIsSelectable="true"
app:layout_constraintEnd_toStartOf="@+id/tvTime"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tvTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:maxLines="1"
android:text="Time"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textIsSelectable="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tvFrom" />
<TextView
android:id="@+id/tvSubject"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:layout_marginStart="6dp"
android:text="Subject"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textIsSelectable="true"
app:layout_constraintEnd_toStartOf="@+id/tvCount"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvFrom" />
<TextView
android:id="@+id/tvCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:maxLines="1"
android:text="3"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="@id/tvSubject" />
<View
android:id="@+id/vSeparator"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="6dp"
android:background="?attr/colorSeparator"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvSubject" />
<TextView
android:id="@+id/tvToTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:maxLines="1"
android:text="@string/title_to"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/vSeparator" />
<TextView
android:id="@+id/tvTo"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:layout_marginStart="6dp"
android:maxLines="1"
android:text="To"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textIsSelectable="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/tvToTitle"
app:layout_constraintTop_toTopOf="@id/tvToTitle" />
<TextView
android:id="@+id/tvCcTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:maxLines="1"
android:text="@string/title_cc"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvTo" />
<TextView
android:id="@+id/tvCc"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:layout_marginStart="6dp"
android:maxLines="1"
android:text="Cc"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textIsSelectable="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/tvCcTitle"
app:layout_constraintTop_toTopOf="@id/tvCcTitle" />
<TextView
android:id="@+id/tvBccTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="6dp"
android:maxLines="1"
android:text="@string/title_bcc"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvCc" />
<TextView
android:id="@+id/tvBcc"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:layout_marginStart="6dp"
android:maxLines="1"
android:text="Bcc"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textIsSelectable="true"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@id/tvBccTitle"
app:layout_constraintTop_toTopOf="@id/tvBccTitle" />
<android.support.design.widget.BottomNavigationView <android.support.design.widget.BottomNavigationView
android:id="@+id/top_navigation" android:id="@+id/top_navigation"
android:layout_width="match_parent" android:layout_width="match_parent"
@ -25,7 +150,7 @@
app:labelVisibilityMode="unlabeled" app:labelVisibilityMode="unlabeled"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/include"
app:layout_constraintTop_toBottomOf="@id/tvBcc"
app:menu="@menu/action_view_top" /> app:menu="@menu/action_view_top" />
<ScrollView <ScrollView
@ -45,7 +170,8 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:fontFamily="monospace" android:fontFamily="monospace"
android:text="Body" android:text="Body"
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textIsSelectable="true" />
</ScrollView> </ScrollView>
<android.support.design.widget.BottomNavigationView <android.support.design.widget.BottomNavigationView
@ -72,9 +198,15 @@
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="parent" /> app:layout_constraintTop_toBottomOf="parent" />
<android.support.constraint.Group
android:id="@+id/grpCc"
android:layout_width="0dp"
android:layout_height="0dp"
app:constraint_referenced_ids="vSeparator,tvToTitle,tvTo,tvCcTitle,tvCc,tvBccTitle,tvBcc" />
<android.support.constraint.Group <android.support.constraint.Group
android:id="@+id/grpReady" android:id="@+id/grpReady"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="0dp" android:layout_height="0dp"
app:constraint_referenced_ids="include,top_navigation,scroll,bottom_navigation" />
app:constraint_referenced_ids="tvFrom,tvTime,tvSubject,tvCount,top_navigation,scroll,bottom_navigation" />
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>

+ 53
- 4
app/src/main/res/layout/item_message.xml View File

@ -5,11 +5,60 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginBottom="6dp"> android:layout_marginBottom="6dp">
<include
android:id="@+id/include"
layout="@layout/message_header"
android:layout_width="match_parent"
<TextView
android:id="@+id/tvFrom"
android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:layout_marginStart="6dp"
android:maxLines="1"
android:text="From"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintEnd_toStartOf="@+id/tvTime"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" /> app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tvTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:maxLines="1"
android:text="Time"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintBottom_toBottomOf="@id/tvFrom"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/tvSubject"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:layout_marginStart="6dp"
android:maxLines="1"
android:text="Subject"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintEnd_toStartOf="@+id/tvCount"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvFrom" />
<TextView
android:id="@+id/tvCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:maxLines="1"
android:text="3"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintBottom_toBottomOf="@id/tvSubject"
app:layout_constraintEnd_toEndOf="parent" />
<View
android:id="@+id/vSeparator"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="6dp"
android:background="?attr/colorSeparator"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvSubject" />
</android.support.constraint.ConstraintLayout> </android.support.constraint.ConstraintLayout>

+ 0
- 63
app/src/main/res/layout/message_header.xml View File

@ -1,63 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tvAddress"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:layout_marginStart="6dp"
android:maxLines="1"
android:text="From"
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintEnd_toStartOf="@+id/tvTime"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="@+id/tvTime"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:maxLines="1"
android:text="Time"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintBottom_toBottomOf="@id/tvAddress"
app:layout_constraintEnd_toEndOf="parent" />
<TextView
android:id="@+id/tvSubject"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:layout_marginStart="6dp"
android:maxLines="1"
android:text="Subject"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintEnd_toStartOf="@+id/tvCount"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvAddress" />
<TextView
android:id="@+id/tvCount"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:maxLines="1"
android:text="3"
android:textAppearance="@style/TextAppearance.AppCompat.Small"
app:layout_constraintBottom_toBottomOf="@id/tvSubject"
app:layout_constraintEnd_toEndOf="parent" />
<View
android:id="@+id/vSeparator"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="6dp"
android:background="?attr/colorSeparator"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/tvSubject" />
</android.support.constraint.ConstraintLayout>

+ 10
- 0
app/src/main/res/menu/menu_cc.xml View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/menu_cc"
android:icon="@drawable/baseline_people_24"
android:title="@string/title_cc"
app:showAsAction="always" />
</menu>

+ 2
- 0
app/src/main/res/values/strings.xml View File

@ -99,6 +99,8 @@
<string name="title_compose">Compose</string> <string name="title_compose">Compose</string>
<string name="title_from">From:</string> <string name="title_from">From:</string>
<string name="title_to">To:</string> <string name="title_to">To:</string>
<string name="title_cc">CC:</string>
<string name="title_bcc">BCC:</string>
<string name="title_subject">Subject:</string> <string name="title_subject">Subject:</string>
<string name="title_body_hint">Your message</string> <string name="title_body_hint">Your message</string>
<string name="title_save">Save</string> <string name="title_save">Save</string>


Loading…
Cancel
Save