Added cc/bcc

This commit is contained in:
M66B 2018-08-03 07:39:43 +00:00
parent bcf86385ae
commit 774f9b3f36
53 changed files with 453 additions and 126 deletions

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_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
protected void onCreate(Bundle savedInstanceState) {

View File

@ -56,7 +56,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
public class ViewHolder extends RecyclerView.ViewHolder
implements View.OnClickListener {
View itemView;
TextView tvAddress;
TextView tvFrom;
TextView tvTime;
TextView tvSubject;
TextView tvCount;
@ -65,7 +65,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
super(itemView);
this.itemView = itemView;
tvAddress = itemView.findViewById(R.id.tvAddress);
tvFrom = itemView.findViewById(R.id.tvFrom);
tvTime = itemView.findViewById(R.id.tvTime);
tvSubject = itemView.findViewById(R.id.tvSubject);
tvCount = itemView.findViewById(R.id.tvCount);
@ -220,10 +220,10 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
TupleMessageEx message = filtered.get(position);
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));
} 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));
}
@ -236,7 +236,7 @@ public class AdapterMessage extends RecyclerView.Adapter<AdapterMessage.ViewHold
boolean unseen = (message.thread == null ? !message.seen : message.unseen > 0);
int visibility = (unseen ? Typeface.BOLD : Typeface.NORMAL);
holder.tvAddress.setTypeface(null, visibility);
holder.tvFrom.setTypeface(null, visibility);
holder.tvTime.setTypeface(null, visibility);
holder.tvSubject.setTypeface(null, visibility);
holder.tvCount.setTypeface(null, visibility);

View File

@ -40,6 +40,8 @@ import android.text.TextUtils;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@ -69,13 +71,18 @@ public class FragmentCompose extends Fragment {
private long rid = -1;
private Spinner spFrom;
private ImageView ivIdentyAdd;
private ImageView ivIdentityAdd;
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 etBody;
private BottomNavigationView bottom_navigation;
private ProgressBar pbWait;
private Group grpCc;
private Group grpReady;
@Override
@ -90,20 +97,26 @@ public class FragmentCompose extends Fragment {
// Get controls
spFrom = view.findViewById(R.id.spFrom);
ivIdentyAdd = view.findViewById(R.id.ivIdentyAdd);
ivIdentityAdd = view.findViewById(R.id.ivIdentityAdd);
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);
etBody = view.findViewById(R.id.etBody);
bottom_navigation = view.findViewById(R.id.bottom_navigation);
pbWait = view.findViewById(R.id.pbWait);
grpCc = view.findViewById(R.id.grpCc);
grpReady = view.findViewById(R.id.grpReady);
grpCc.setVisibility(View.GONE);
etBody.setMovementMethod(LinkMovementMethod.getInstance());
// Wire controls
ivIdentyAdd.setOnClickListener(new View.OnClickListener() {
ivIdentityAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Bundle args = new Bundle();
@ -116,11 +129,27 @@ public class FragmentCompose extends Fragment {
}
});
ivContactAdd.setOnClickListener(new View.OnClickListener() {
ivToAdd.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);
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
grpReady.setVisibility(View.GONE);
pbWait.setVisibility(View.VISIBLE);
@ -185,9 +216,30 @@ public class FragmentCompose extends Fragment {
((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
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == ActivityCompose.REQUEST_CONTACT && resultCode == RESULT_OK) {
if (resultCode == RESULT_OK) {
Cursor cursor = null;
try {
cursor = getContext().getContentResolver().query(data.getData(),
@ -202,12 +254,26 @@ public class FragmentCompose extends Fragment {
String email = cursor.getString(colEmail);
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);
StringBuilder sb = new StringBuilder(etTo.getText().toString());
StringBuilder sb = new StringBuilder(text);
if (sb.length() > 0)
sb.append("; ");
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) {
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.putLong("rid", FragmentCompose.this.rid);
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("body", etBody.getText().toString());
args.putBoolean("send", send);
@ -270,6 +338,8 @@ public class FragmentCompose extends Fragment {
result.putLong("iid", msg.identity);
if (msg.replying != null)
result.putLong("rid", msg.replying);
result.putString("cc", msg.cc);
result.putString("bcc", msg.bcc);
result.putString("thread", msg.thread);
result.putString("subject", msg.subject);
result.putString("body", msg.body);
@ -339,6 +409,8 @@ public class FragmentCompose extends Fragment {
String thread = result.getString("thread");
String from = result.getString("from");
String to = result.getString("to");
String cc = result.getString("cc");
String bcc = result.getString("bcc");
String subject = result.getString("subject");
String body = result.getString("body");
String action = result.getString("action");
@ -363,9 +435,11 @@ public class FragmentCompose extends Fragment {
// Prevent changed fields from being overwritten
once = true;
etCc.setText(TextUtils.join(", ", MessageHelper.decodeAddresses(cc)));
etBcc.setText(TextUtils.join(", ", MessageHelper.decodeAddresses(bcc)));
if (action == null) {
if (to != null)
etTo.setText(TextUtils.join(", ", MessageHelper.decodeAddresses(to)));
etTo.setText(TextUtils.join(", ", MessageHelper.decodeAddresses(to)));
etSubject.setText(subject);
if (body != null)
etBody.setText(Html.fromHtml(HtmlHelper.sanitize(getContext(), body, false)));
@ -480,11 +554,15 @@ public class FragmentCompose extends Fragment {
long rid = args.getLong("rid", -1);
String thread = args.getString("thread");
String to = args.getString("to");
String cc = args.getString("cc");
String bcc = args.getString("bcc");
String body = args.getString("body");
String subject = args.getString("subject");
Address afrom = (ident == null ? null : new InternetAddress(ident.email, ident.name));
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
boolean update = (draft != null);
@ -495,8 +573,10 @@ public class FragmentCompose extends Fragment {
draft.identity = (ident == null ? null : ident.id);
draft.replying = (rid < 0 ? null : rid);
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.body = "<pre>" + body.replaceAll("\\r?\\n", "<br />") + "</pre>";
draft.received = new Date().getTime();
@ -514,7 +594,7 @@ public class FragmentCompose extends Fragment {
if (send) {
if (draft.identity == null)
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));
// Get outbox
@ -536,6 +616,8 @@ public class FragmentCompose extends Fragment {
out.thread = draft.thread;
out.from = draft.from;
out.to = draft.to;
out.cc = draft.cc;
out.bcc = draft.bcc;
out.subject = draft.subject;
out.body = draft.body;
out.received = draft.received;

View File

@ -37,6 +37,8 @@ import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
@ -53,12 +55,16 @@ import java.util.concurrent.Executors;
public class FragmentMessage extends Fragment {
private TextView tvTime;
private TextView tvFrom;
private TextView tvTo;
private TextView tvCc;
private TextView tvBcc;
private TextView tvSubject;
private TextView tvCount;
private BottomNavigationView top_navigation;
private TextView tvBody;
private BottomNavigationView bottom_navigation;
private ProgressBar pbWait;
private Group grpCc;
private Group grpReady;
private LiveData<TupleFolderEx> liveFolder;
@ -77,7 +83,10 @@ public class FragmentMessage extends Fragment {
final long id = args.getLong("id");
// 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);
tvSubject = view.findViewById(R.id.tvSubject);
tvCount = view.findViewById(R.id.tvCount);
@ -85,12 +94,10 @@ public class FragmentMessage extends Fragment {
tvBody = view.findViewById(R.id.tvBody);
bottom_navigation = view.findViewById(R.id.bottom_navigation);
pbWait = view.findViewById(R.id.pbWait);
grpCc = view.findViewById(R.id.grpCc);
grpReady = view.findViewById(R.id.grpReady);
tvTime.setTextIsSelectable(true);
tvFrom.setTextIsSelectable(true);
tvSubject.setTextIsSelectable(true);
tvBody.setTextIsSelectable(true);
setHasOptionsMenu(true);
tvBody.setMovementMethod(LinkMovementMethod.getInstance());
// Wire controls
@ -141,6 +148,7 @@ public class FragmentMessage extends Fragment {
});
// Initialize
grpCc.setVisibility(View.GONE);
grpReady.setVisibility(View.GONE);
pbWait.setVisibility(View.VISIBLE);
@ -161,7 +169,10 @@ public class FragmentMessage extends Fragment {
if (FragmentMessage.this.isVisible())
getFragmentManager().popBackStack();
} 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)));
tvSubject.setText(message.subject);
tvCount.setText(Integer.toString(message.count));
@ -203,6 +214,27 @@ public class FragmentMessage extends Fragment {
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>() {
@Override
public void onChanged(@Nullable TupleFolderEx folder) {

View File

@ -90,7 +90,10 @@ public class MessageHelper {
imessage.setRecipients(Message.RecipientType.TO, MessageHelper.decodeAddresses(message.to));
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)
imessage.setSubject(message.subject);
@ -153,11 +156,17 @@ public class MessageHelper {
return encodeAddresses(imessage.getRecipients(Message.RecipientType.CC));
}
String getBcc() throws MessagingException, JSONException {
return encodeAddresses(imessage.getRecipients(Message.RecipientType.BCC));
}
String getReply() throws MessagingException, JSONException {
return encodeAddresses(imessage.getReplyTo());
}
static String encodeAddresses(Address[] addresses) throws JSONException {
if (addresses == null)
return null;
JSONArray jaddresses = new JSONArray();
if (addresses != null)
for (Address address : addresses)
@ -175,23 +184,24 @@ public class MessageHelper {
}
static Address[] decodeAddresses(String json) {
if (json == null)
return new Address[0];
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]);
}
@ -200,6 +210,8 @@ public class MessageHelper {
}
static String getFormattedAddresses(String json) {
if (json == null)
return null;
try {
List<String> addresses = new ArrayList<>();
for (Address address : decodeAddresses(json))

View File

@ -639,7 +639,7 @@ public class ServiceSynchronize extends LifecycleService {
try {
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);
Log.i(Helper.TAG, "Sent via " + ident.host + "/" + ident.user +
" to " + TextUtils.join(", ", to));
@ -680,14 +680,14 @@ public class ServiceSynchronize extends LifecycleService {
names.add(folder.name);
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);
for (Folder ifolder : ifolders) {
String[] attrs = ((IMAPFolder) ifolder).getAttributes();
boolean candidate = true;
for (String attr : attrs) {
if ("\\Noselect".equals(attr)) {
if ("\\Noselect".equals(attr)) { // TODO: is this attribute correct?
candidate = false;
break;
}
@ -844,7 +844,7 @@ public class ServiceSynchronize extends LifecycleService {
message.from = helper.getFrom();
message.to = helper.getTo();
message.cc = helper.getCc();
message.bcc = null;
message.bcc = helper.getBcc();
message.reply = helper.getReply();
message.subject = imessage.getSubject();
message.body = helper.getHtml();

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 184 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 317 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 260 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 313 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 355 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 353 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 632 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 430 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 567 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 838 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 554 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 827 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

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>

View File

@ -14,11 +14,13 @@
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/ivIdentyAdd"
android:id="@+id/ivIdentityAdd"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginEnd="6dp"
android:layout_marginStart="6dp"
android:src="@drawable/baseline_person_add_24"
app:layout_constraintBottom_toBottomOf="@id/spFrom"
app:layout_constraintStart_toEndOf="@id/spFrom"
app:layout_constraintTop_toTopOf="@id/spFrom" />
@ -31,21 +33,72 @@
android:inputType="textEmailAddress"
android:maxLines="1"
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_constraintTop_toBottomOf="@+id/spFrom" />
<ImageView
android:id="@+id/ivContactAdd"
android:id="@+id/ivToAdd"
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/etTo"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@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
android:id="@+id/etSubject"
android:layout_width="0dp"
@ -58,7 +111,7 @@
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/etTo" />
app:layout_constraintTop_toBottomOf="@+id/etBcc" />
<View
android:id="@+id/vSeparator"
@ -117,9 +170,15 @@
app:layout_constraintStart_toStartOf="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:id="@+id/grpReady"
android:layout_width="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>

View File

@ -7,14 +7,139 @@
android:orientation="vertical"
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_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_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:id="@+id/top_navigation"
android:layout_width="match_parent"
@ -25,7 +150,7 @@
app:labelVisibilityMode="unlabeled"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/include"
app:layout_constraintTop_toBottomOf="@id/tvBcc"
app:menu="@menu/action_view_top" />
<ScrollView
@ -45,7 +170,8 @@
android:layout_height="match_parent"
android:fontFamily="monospace"
android:text="Body"
android:textAppearance="@style/TextAppearance.AppCompat.Small" />
android:textAppearance="@style/TextAppearance.AppCompat.Small"
android:textIsSelectable="true" />
</ScrollView>
<android.support.design.widget.BottomNavigationView
@ -72,9 +198,15 @@
app:layout_constraintStart_toStartOf="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:id="@+id/grpReady"
android:layout_width="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>

View File

@ -5,11 +5,60 @@
android:layout_height="wrap_content"
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_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/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>

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>

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>

View File

@ -99,6 +99,8 @@
<string name="title_compose">Compose</string>
<string name="title_from">From:</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_body_hint">Your message</string>
<string name="title_save">Save</string>