diff --git a/TODO b/TODO index 2878839..81fa4d0 100644 --- a/TODO +++ b/TODO @@ -23,8 +23,6 @@ Features: - Public address book lookup - "Write email" link in address book - Add optional CC: and BCC: fields -- Forward -- Reply all - Attachments - QR codes for identities - "Empty trash" option in Trash folder diff --git a/app/src/main/java/i2p/bote/android/NewEmailActivity.java b/app/src/main/java/i2p/bote/android/NewEmailActivity.java index a3d4d8c..35e64e6 100644 --- a/app/src/main/java/i2p/bote/android/NewEmailActivity.java +++ b/app/src/main/java/i2p/bote/android/NewEmailActivity.java @@ -19,14 +19,17 @@ public class NewEmailActivity extends ActionBarActivity implements getSupportActionBar().setDisplayHomeAsUpEnabled(true); if (savedInstanceState == null) { - String quoteMsgFolder = null; - String quoteMsgId = null; + NewEmailFragment f; Bundle args = getIntent().getExtras(); if (args != null) { - quoteMsgFolder = args.getString(NewEmailFragment.QUOTE_MSG_FOLDER); - quoteMsgId = args.getString(NewEmailFragment.QUOTE_MSG_ID); + String quoteMsgFolder = args.getString(NewEmailFragment.QUOTE_MSG_FOLDER); + String quoteMsgId = args.getString(NewEmailFragment.QUOTE_MSG_ID); + NewEmailFragment.QuoteMsgType quoteMsgType = + (NewEmailFragment.QuoteMsgType) args.getSerializable(NewEmailFragment.QUOTE_MSG_TYPE); + f = NewEmailFragment.newInstance(quoteMsgFolder, quoteMsgId, quoteMsgType); + } else { + f = new NewEmailFragment(); } - NewEmailFragment f = NewEmailFragment.newInstance(quoteMsgFolder, quoteMsgId); getSupportFragmentManager().beginTransaction() .add(android.R.id.content, f).commit(); } diff --git a/app/src/main/java/i2p/bote/android/NewEmailFragment.java b/app/src/main/java/i2p/bote/android/NewEmailFragment.java index fcea528..33f2a98 100644 --- a/app/src/main/java/i2p/bote/android/NewEmailFragment.java +++ b/app/src/main/java/i2p/bote/android/NewEmailFragment.java @@ -52,7 +52,7 @@ public class NewEmailFragment extends Fragment { public void onTaskFinished(); } private static Callbacks sDummyCallbacks = new Callbacks() { - public void onTaskFinished() {}; + public void onTaskFinished() {} }; @Override @@ -71,6 +71,12 @@ public class NewEmailFragment extends Fragment { public static final String QUOTE_MSG_FOLDER = "sender"; public static final String QUOTE_MSG_ID = "recipient"; + public static enum QuoteMsgType { + REPLY, + REPLY_ALL, + FORWARD + } + public static final String QUOTE_MSG_TYPE = "type"; private String mSenderKey; @@ -81,11 +87,13 @@ public class NewEmailFragment extends Fragment { EditText mSubject; EditText mContent; - public static NewEmailFragment newInstance(String quoteMsgFolder, String quoteMsgId) { + public static NewEmailFragment newInstance(String quoteMsgFolder, String quoteMsgId, + QuoteMsgType quoteMsgType) { NewEmailFragment f = new NewEmailFragment(); Bundle args = new Bundle(); args.putString(QUOTE_MSG_FOLDER, quoteMsgFolder); args.putString(QUOTE_MSG_ID, quoteMsgId); + args.putSerializable(QUOTE_MSG_TYPE, quoteMsgType); f.setArguments(args); return f; } @@ -106,39 +114,45 @@ public class NewEmailFragment extends Fragment { public void onViewCreated(View view, Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); + mSpinner = (Spinner) view.findViewById(R.id.sender_spinner); + mRecipients = (ContactsCompletionView) view.findViewById(R.id.recipients); + mSubject = (EditText) view.findViewById(R.id.subject); + mContent = (EditText) view.findViewById(R.id.message); + String quoteMsgFolder = getArguments().getString(QUOTE_MSG_FOLDER); String quoteMsgId = getArguments().getString(QUOTE_MSG_ID); - Email origEmail = null; - String recipientName = null; - String recipientAddr = null; - Bitmap recipientPic = null; + QuoteMsgType quoteMsgType = (QuoteMsgType) getArguments().getSerializable(QUOTE_MSG_TYPE); + boolean hide = I2PBote.getInstance().getConfiguration().getHideLocale(); + + List recipients = new ArrayList(); String origSubject = null; String origContent = null; String origFrom = null; try { - origEmail = BoteHelper.getEmail(quoteMsgFolder, quoteMsgId); + Email origEmail = BoteHelper.getEmail(quoteMsgFolder, quoteMsgId); + if (origEmail != null) { mSenderKey = BoteHelper.extractEmailDestination( BoteHelper.getOneLocalRecipient(origEmail).toString()); - String recipient = BoteHelper.getNameAndDestination( - origEmail.getReplyAddress(I2PBote.getInstance().getIdentities())); - recipientName = BoteHelper.extractName(recipient); - recipientAddr = BoteHelper.extractEmailDestination(recipient); - if (recipientAddr == null) { // Assume external address - recipientAddr = recipient; - if (recipientName.isEmpty()) - recipientName = recipientAddr; - } else { - if (recipientName.isEmpty()) // Dest with no name - recipientName = recipientAddr.substring(0, 5); - recipientPic = BoteHelper.getPictureForDestination(recipientAddr); + + if (quoteMsgType == QuoteMsgType.REPLY) { + String recipient = BoteHelper.getNameAndDestination( + origEmail.getReplyAddress(I2PBote.getInstance().getIdentities())); + recipients.add(extractPerson(recipient)); + } else if (quoteMsgType == QuoteMsgType.REPLY_ALL) { + // TODO don't include our address + // What happens if an email is received by multiple local identities? + for (Address address : origEmail.getAllAddresses(true)) { + recipients.add(extractPerson(address.toString())); + } } + origSubject = origEmail.getSubject(); origContent = origEmail.getText(); origFrom = BoteHelper.getShortSenderName(origEmail.getOneFromAddress(), 50); } } catch (PasswordException e) { - // TODO Auto-generated catch block + // Should not happen, we cannot get to this page without authenticating e.printStackTrace(); } catch (IOException e) { // TODO Auto-generated catch block @@ -151,11 +165,12 @@ public class NewEmailFragment extends Fragment { e.printStackTrace(); } - mSpinner = (Spinner) view.findViewById(R.id.sender_spinner); + // Set up identities spinner IdentityAdapter identities = new IdentityAdapter(getActivity()); mSpinner.setAdapter(identities); mSpinner.setSelection(mDefaultPos); + // Set up contacts auto-complete List contacts = new ArrayList(); try { for (Contact contact : I2PBote.getInstance().getAddressBook().getAll()) { @@ -192,21 +207,24 @@ public class NewEmailFragment extends Fragment { } }; - mRecipients = (ContactsCompletionView) view.findViewById(R.id.recipients); mRecipients.setAdapter(mAdapter); - if (recipientAddr != null) { - mRecipients.addObject(new Person(recipientName, recipientAddr, recipientPic)); + for (Person recipient : recipients) { + mRecipients.addObject(recipient); } - mSubject = (EditText) view.findViewById(R.id.subject); - mContent = (EditText) view.findViewById(R.id.message); - boolean hide = I2PBote.getInstance().getConfiguration().getHideLocale(); if (origSubject != null) { - String responsePrefix = getResources().getString( - hide ? R.string.response_prefix_re_hide - : R.string.response_prefix_re); - if (!origSubject.startsWith(responsePrefix)) - origSubject = responsePrefix + " " + origSubject; + String subjectPrefix; + if (quoteMsgType == QuoteMsgType.FORWARD) { + subjectPrefix = getResources().getString( + hide ? R.string.subject_prefix_fwd_hide + : R.string.subject_prefix_fwd); + } else { + subjectPrefix = getResources().getString( + hide ? R.string.response_prefix_re_hide + : R.string.response_prefix_re); + } + if (!origSubject.startsWith(subjectPrefix)) + origSubject = subjectPrefix + " " + origSubject; mSubject.setText(origSubject); } if (origContent != null) { @@ -227,6 +245,31 @@ public class NewEmailFragment extends Fragment { } } + private Person extractPerson(String recipient) { + String recipientName = BoteHelper.extractName(recipient); + String recipientAddr = BoteHelper.extractEmailDestination(recipient); + if (recipientAddr == null) { // Assume external address + recipientAddr = recipient; + if (recipientName.isEmpty()) + recipientName = recipientAddr; + return new Person(recipientName, recipientAddr, null, true); + } else { + if (recipientName.isEmpty()) // Dest with no name + recipientName = recipientAddr.substring(0, 5); + Bitmap recipientPic = null; + try { + recipientPic = BoteHelper.getPictureForDestination(recipientAddr); + } catch (PasswordException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } catch (GeneralSecurityException e) { + e.printStackTrace(); + } + return new Person(recipientName, recipientAddr, recipientPic); + } + } + @Override public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { inflater.inflate(R.menu.new_email, menu); diff --git a/app/src/main/java/i2p/bote/android/ViewEmailFragment.java b/app/src/main/java/i2p/bote/android/ViewEmailFragment.java index a2a77ec..8630319 100644 --- a/app/src/main/java/i2p/bote/android/ViewEmailFragment.java +++ b/app/src/main/java/i2p/bote/android/ViewEmailFragment.java @@ -144,15 +144,29 @@ public class ViewEmailFragment extends Fragment { @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { - case R.id.action_reply: - Intent nei = new Intent(getActivity(), NewEmailActivity.class); - nei.putExtra(NewEmailFragment.QUOTE_MSG_FOLDER, mFolderName); - nei.putExtra(NewEmailFragment.QUOTE_MSG_ID, mMessageId); - startActivity(nei); - return true; + case R.id.action_reply: + case R.id.action_reply_all: + case R.id.action_forward: + Intent nei = new Intent(getActivity(), NewEmailActivity.class); + nei.putExtra(NewEmailFragment.QUOTE_MSG_FOLDER, mFolderName); + nei.putExtra(NewEmailFragment.QUOTE_MSG_ID, mMessageId); + NewEmailFragment.QuoteMsgType type = null; + switch (item.getItemId()) { + case R.id.action_reply: + type = NewEmailFragment.QuoteMsgType.REPLY; + break; + case R.id.action_reply_all: + type = NewEmailFragment.QuoteMsgType.REPLY_ALL; + break; + case R.id.action_forward: + type = NewEmailFragment.QuoteMsgType.FORWARD; + } + nei.putExtra(NewEmailFragment.QUOTE_MSG_TYPE, type); + startActivity(nei); + return true; - default: - return super.onOptionsItemSelected(item); + default: + return super.onOptionsItemSelected(item); } } } diff --git a/app/src/main/res/drawable-hdpi/ic_social_forward.png b/app/src/main/res/drawable-hdpi/ic_social_forward.png new file mode 100644 index 0000000..bed191d Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_social_forward.png differ diff --git a/app/src/main/res/drawable-hdpi/ic_social_reply_all.png b/app/src/main/res/drawable-hdpi/ic_social_reply_all.png new file mode 100644 index 0000000..7ee22a8 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/ic_social_reply_all.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_social_forward.png b/app/src/main/res/drawable-mdpi/ic_social_forward.png new file mode 100644 index 0000000..d9f321f Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_social_forward.png differ diff --git a/app/src/main/res/drawable-mdpi/ic_social_reply_all.png b/app/src/main/res/drawable-mdpi/ic_social_reply_all.png new file mode 100644 index 0000000..721ac9b Binary files /dev/null and b/app/src/main/res/drawable-mdpi/ic_social_reply_all.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_social_forward.png b/app/src/main/res/drawable-xhdpi/ic_social_forward.png new file mode 100644 index 0000000..340ce9a Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_social_forward.png differ diff --git a/app/src/main/res/drawable-xhdpi/ic_social_reply_all.png b/app/src/main/res/drawable-xhdpi/ic_social_reply_all.png new file mode 100644 index 0000000..ea39a1c Binary files /dev/null and b/app/src/main/res/drawable-xhdpi/ic_social_reply_all.png differ diff --git a/app/src/main/res/menu/view_email.xml b/app/src/main/res/menu/view_email.xml index 7272a78..8ab8694 100644 --- a/app/src/main/res/menu/view_email.xml +++ b/app/src/main/res/menu/view_email.xml @@ -8,4 +8,16 @@ android:title="@string/reply" i2pandroid:showAsAction="ifRoom"/> + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 712eac6..f667749 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -102,11 +102,15 @@ Received: Status: Reply + Reply all + Forward Compose Subject Compose email Add at least one recipient. Email queued for sending + Fwd: + Fwd: Re: Re: