diff --git a/res/drawable-hdpi/ic_collections_collection.png b/res/drawable-hdpi/ic_collections_collection.png new file mode 100644 index 0000000..6f441b4 Binary files /dev/null and b/res/drawable-hdpi/ic_collections_collection.png differ diff --git a/res/drawable-hdpi/ic_content_read.png b/res/drawable-hdpi/ic_content_read.png new file mode 100644 index 0000000..9ef5295 Binary files /dev/null and b/res/drawable-hdpi/ic_content_read.png differ diff --git a/res/drawable-hdpi/ic_content_unread.png b/res/drawable-hdpi/ic_content_unread.png new file mode 100644 index 0000000..d516f77 Binary files /dev/null and b/res/drawable-hdpi/ic_content_unread.png differ diff --git a/res/drawable-mdpi/ic_collections_collection.png b/res/drawable-mdpi/ic_collections_collection.png new file mode 100644 index 0000000..cc81e57 Binary files /dev/null and b/res/drawable-mdpi/ic_collections_collection.png differ diff --git a/res/drawable-mdpi/ic_content_read.png b/res/drawable-mdpi/ic_content_read.png new file mode 100644 index 0000000..0f59a03 Binary files /dev/null and b/res/drawable-mdpi/ic_content_read.png differ diff --git a/res/drawable-mdpi/ic_content_unread.png b/res/drawable-mdpi/ic_content_unread.png new file mode 100644 index 0000000..eff1ba3 Binary files /dev/null and b/res/drawable-mdpi/ic_content_unread.png differ diff --git a/res/drawable-xhdpi/ic_collections_collection.png b/res/drawable-xhdpi/ic_collections_collection.png new file mode 100644 index 0000000..78500a9 Binary files /dev/null and b/res/drawable-xhdpi/ic_collections_collection.png differ diff --git a/res/drawable-xhdpi/ic_content_read.png b/res/drawable-xhdpi/ic_content_read.png new file mode 100644 index 0000000..62e3d1a Binary files /dev/null and b/res/drawable-xhdpi/ic_content_read.png differ diff --git a/res/drawable-xhdpi/ic_content_unread.png b/res/drawable-xhdpi/ic_content_unread.png new file mode 100644 index 0000000..606c902 Binary files /dev/null and b/res/drawable-xhdpi/ic_content_unread.png differ diff --git a/res/menu/email_list_context.xml b/res/menu/email_list_context.xml index 57bcfd0..2d1c013 100644 --- a/res/menu/email_list_context.xml +++ b/res/menu/email_list_context.xml @@ -3,9 +3,24 @@ xmlns:i2pandroid="http://schemas.android.com/apk/res-auto" > + + + \ No newline at end of file diff --git a/res/values/strings.xml b/res/values/strings.xml index 826ed6d..71a71e2 100644 --- a/res/values/strings.xml +++ b/res/values/strings.xml @@ -7,7 +7,10 @@ Settings %s selected - Delete selected emails + Delete + Mark read + Mark unread + Move to Open nav Close nav diff --git a/src/i2p/bote/EmailListActivity.java b/src/i2p/bote/EmailListActivity.java index bdc3982..eed84e8 100644 --- a/src/i2p/bote/EmailListActivity.java +++ b/src/i2p/bote/EmailListActivity.java @@ -3,6 +3,7 @@ package i2p.bote; import net.i2p.client.I2PClient; import i2p.bote.config.SettingsActivity; import i2p.bote.folder.EmailFolder; +import i2p.bote.util.MoveToDialogFragment; import android.os.Bundle; import android.preference.PreferenceManager; import android.content.Context; @@ -20,7 +21,8 @@ import android.widget.AdapterView; import android.widget.ListView; public class EmailListActivity extends ActionBarActivity implements - EmailListFragment.OnEmailSelectedListener { + EmailListFragment.OnEmailSelectedListener, + MoveToDialogFragment.MoveToDialogListener { private CharSequence mDrawerTitle; private CharSequence mTitle; private SharedPreferences mSharedPrefs; @@ -224,4 +226,12 @@ public class EmailListActivity extends ActionBarActivity implements detailIntent.putExtra(ViewEmailActivity.MESSAGE_ID, messageId); startActivity(detailIntent); } + + // MoveToDialogFragment.MoveToDialogListener + + @Override + public void onFolderSelected(EmailFolder newFolder) { + EmailListFragment f = (EmailListFragment) getSupportFragmentManager().findFragmentById(R.id.list_fragment); + f.onFolderSelected(newFolder); + } } diff --git a/src/i2p/bote/EmailListFragment.java b/src/i2p/bote/EmailListFragment.java index 2ef65f3..11a7b30 100644 --- a/src/i2p/bote/EmailListFragment.java +++ b/src/i2p/bote/EmailListFragment.java @@ -13,6 +13,7 @@ import i2p.bote.folder.EmailFolder; import i2p.bote.folder.FolderListener; import i2p.bote.util.BetterAsyncTaskLoader; import i2p.bote.util.BoteHelper; +import i2p.bote.util.MoveToDialogFragment; import android.app.Activity; import android.app.AlertDialog; import android.app.ProgressDialog; @@ -21,6 +22,7 @@ import android.content.DialogInterface; import android.content.Intent; import android.os.AsyncTask; import android.os.Bundle; +import android.support.v4.app.DialogFragment; import android.support.v4.app.ListFragment; import android.support.v4.app.LoaderManager; import android.support.v4.content.Loader; @@ -39,7 +41,8 @@ import android.widget.ListView; import android.widget.TextView; public class EmailListFragment extends ListFragment implements - LoaderManager.LoaderCallbacks> { + LoaderManager.LoaderCallbacks>, + MoveToDialogFragment.MoveToDialogListener { public static final String FOLDER_NAME = "folder_name"; private static final int EMAIL_LIST_LOADER = 1; @@ -244,7 +247,8 @@ public class EmailListFragment extends ListFragment implements boolean hasCheckedElement = mAdapter.getSelectedCount() > 0; if (hasCheckedElement && mMode == null) { - mMode = ((ActionBarActivity) getActivity()).startSupportActionMode(new ModeCallback()); + boolean unread = mAdapter.getItem(position).isNew(); + mMode = ((ActionBarActivity) getActivity()).startSupportActionMode(new ModeCallback(unread)); } else if (!hasCheckedElement && mMode != null) { mMode.finish(); } @@ -255,21 +259,53 @@ public class EmailListFragment extends ListFragment implements } private final class ModeCallback implements ActionMode.Callback { + private boolean areUnread; + + public ModeCallback(boolean unread) { + super(); + this.areUnread = unread; + } + @Override public boolean onActionItemClicked(ActionMode mode, MenuItem item) { // Respond to clicks on the actions in the CAB switch (item.getItemId()) { - case R.id.action_delete_emails: - SparseBooleanArray selected = mAdapter.getSelectedIds(); - for (int i = (selected.size() - 1); i >= 0; i--) { - if (selected.valueAt(i)) { - Email email = mAdapter.getItem(selected.keyAt(i)); + case R.id.action_delete: + SparseBooleanArray toDelete = mAdapter.getSelectedIds(); + for (int i = (toDelete.size() - 1); i >= 0; i--) { + if (toDelete.valueAt(i)) { + Email email = mAdapter.getItem(toDelete.keyAt(i)); // The Loader will update mAdapter I2PBote.getInstance().deleteEmail(mFolder, email.getMessageID()); } } mode.finish(); return true; + case R.id.action_mark_read: + case R.id.action_mark_unread: + SparseBooleanArray selected = mAdapter.getSelectedIds(); + for (int i = (selected.size() - 1); i >= 0; i--) { + if (selected.valueAt(i)) { + Email email = mAdapter.getItem(selected.keyAt(i)); + try { + // The Loader will update mAdapter + mFolder.setNew(email, !areUnread); + } catch (PasswordException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } catch (GeneralSecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + } + areUnread = !areUnread; + mMode.invalidate(); + return true; + case R.id.action_move_to: + DialogFragment f = MoveToDialogFragment.newInstance(mFolder); + f.show(getFragmentManager(), "moveTo"); + return true; default: return false; } @@ -297,10 +333,25 @@ public class EmailListFragment extends ListFragment implements public boolean onPrepareActionMode(ActionMode mode, Menu menu) { // Here you can perform updates to the CAB due to // an invalidate() request - return false; + menu.findItem(R.id.action_mark_read).setVisible(areUnread); + menu.findItem(R.id.action_mark_unread).setVisible(!areUnread); + return true; } } + // Called by EmailListActivity.onFolderSelected() + + public void onFolderSelected(EmailFolder newFolder) { + SparseBooleanArray toMove = mAdapter.getSelectedIds(); + for (int i = (toMove.size() - 1); i >= 0; i--) { + if (toMove.valueAt(i)) { + Email email = mAdapter.getItem(toMove.keyAt(i)); + mFolder.move(email, newFolder); + } + } + mMode.finish(); + } + // LoaderManager.LoaderCallbacks> public Loader> onCreateLoader(int id, Bundle args) { @@ -345,6 +396,11 @@ public class EmailListFragment extends ListFragment implements onContentChanged(); } + @Override + public void elementUpdated() { + onContentChanged(); + } + @Override public void elementRemoved() { onContentChanged(); diff --git a/src/i2p/bote/FolderListAdapter.java b/src/i2p/bote/FolderListAdapter.java index 1f98e1b..b381d2a 100644 --- a/src/i2p/bote/FolderListAdapter.java +++ b/src/i2p/bote/FolderListAdapter.java @@ -57,6 +57,11 @@ public class FolderListAdapter extends ArrayAdapter implements Fold notifyDataSetChanged(); } + @Override + public void elementUpdated() { + notifyDataSetChanged(); + } + @Override public void elementRemoved() { notifyDataSetChanged(); diff --git a/src/i2p/bote/ViewEmailActivity.java b/src/i2p/bote/ViewEmailActivity.java index 1febbaa..328736f 100644 --- a/src/i2p/bote/ViewEmailActivity.java +++ b/src/i2p/bote/ViewEmailActivity.java @@ -154,6 +154,11 @@ public class ViewEmailActivity extends ActionBarActivity implements onContentChanged(); } + @Override + public void elementUpdated() { + onContentChanged(); + } + @Override public void elementRemoved() { onContentChanged(); diff --git a/src/i2p/bote/util/BoteHelper.java b/src/i2p/bote/util/BoteHelper.java index 42a04c1..c15ed2b 100644 --- a/src/i2p/bote/util/BoteHelper.java +++ b/src/i2p/bote/util/BoteHelper.java @@ -10,7 +10,6 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.Base64; -import i2p.bote.I2PBote; import i2p.bote.R; import i2p.bote.email.EmailDestination; import i2p.bote.email.EmailIdentity; diff --git a/src/i2p/bote/util/MoveToDialogFragment.java b/src/i2p/bote/util/MoveToDialogFragment.java new file mode 100644 index 0000000..ce32269 --- /dev/null +++ b/src/i2p/bote/util/MoveToDialogFragment.java @@ -0,0 +1,84 @@ +package i2p.bote.util; + +import i2p.bote.I2PBote; +import i2p.bote.R; +import i2p.bote.folder.EmailFolder; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import android.app.Activity; +import android.app.AlertDialog; +import android.app.Dialog; +import android.content.DialogInterface; +import android.os.Bundle; +import android.support.v4.app.DialogFragment; + +public class MoveToDialogFragment extends DialogFragment { + public static final String CURRENT_FOLDER = "current_folder"; + + public static MoveToDialogFragment newInstance(EmailFolder currentFolder) { + MoveToDialogFragment f = new MoveToDialogFragment(); + Bundle args = new Bundle(); + args.putString(CURRENT_FOLDER, currentFolder.getName()); + f.setArguments(args); + return f; + } + + public interface MoveToDialogListener { + public void onFolderSelected(EmailFolder newFolder); + } + + MoveToDialogListener mListener; + List mFolders; + List mFolderDisplayNames; + + @Override + public void onAttach(Activity activity) { + super.onAttach(activity); + try { + mListener = (MoveToDialogListener) activity; + } catch (ClassCastException e) { + throw new ClassCastException(activity.toString() + + " must implement MoveToDialogListener"); + } + } + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + mFolders = I2PBote.getInstance().getEmailFolders(); + mFolderDisplayNames = new ArrayList(); + + String curFolder = getArguments().getString(CURRENT_FOLDER); + Iterator i = mFolders.iterator(); + while (i.hasNext()) { + EmailFolder folder = i.next(); + if (folder.getName().equals(curFolder)) + i.remove(); + else + mFolderDisplayNames.add( + BoteHelper.getFolderDisplayName(getActivity(), folder)); + } + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + AlertDialog.Builder builder = new AlertDialog.Builder(getActivity()); + builder.setTitle(R.string.action_move_to) + .setItems(mFolderDisplayNames.toArray(new String[mFolderDisplayNames.size()]), + new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + mListener.onFolderSelected(mFolders.get(which)); + } + }) + .setNegativeButton(android.R.string.cancel, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int id) { + dialog.cancel(); + } + }); + return builder.create(); + } +}